Passing *this by value

88 views
Skip to first unread message

Marc Mutz

unread,
Mar 24, 2017, 10:20:17 AM3/24/17
to ISO C++ Standard - Future Proposals
Hi,

On the Qt development mailing lists we're currently discussing the pros and
cons of member functions vs. free functions. One thing that came up there is
that member functions, if not inline(d), force the object into memory by way
of passing *this by reference (pointer). A free function otoh, can choose to
take the same parameter by value, which means that it may be passed in
registers.

Chandler has included this example in his BoostCon 2013 talk, too:
Larger context:
https://youtu.be/eR34r7HOU14?t=2021
Actual example:
https://youtu.be/eR34r7HOU14?t=3821

So, I thought, why not add a mechanism by which a class author can indicate
that *this should be passed by value?

Here's Chandler's example rewritten:

struct S {
float x, y, z;
double compute() const =; // internally: double S::compute(S this)
// = mickicks:
double compute2() const &; // *this is lvalue reference
double compute2() &&; // *this is rvalue reference
};

double f() {
S s;
// ...
s.compute(); // efficient now, S not forced into memory, can be passed
// in four registers (on most architectures)
}

There are a lot of open ends here, of course, but you should get the idea.
Should I turn this into a proposal?

Thanks,
Marc

--
Marc Mutz <marc...@kdab.com> | Senior Software Engineer
KDAB (Deutschland) GmbH & Co.KG, a KDAB Group Company
Tel: +49-30-521325470
KDAB - The Qt, C++ and OpenGL Experts

Arthur O'Dwyer

unread,
Mar 24, 2017, 6:35:09 PM3/24/17
to ISO C++ Standard - Future Proposals
On Friday, March 24, 2017 at 7:20:17 AM UTC-7, Marc Mutz wrote:
Hi,

On the Qt development mailing lists we're currently discussing the pros and
cons of member functions vs. free functions. One thing that came up there is
that member functions, if not inline(d), force the object into memory by way
of passing *this by reference (pointer). A free function otoh, can choose to
take the same parameter by value, which means that it may be passed in
registers. [...]

So, I thought, why not add a mechanism by which a class author can indicate
that *this should be passed by value?

  struct S {
      float x, y, z;
      double compute() const =; // internally: double S::compute(S this)
  };

There are a lot of open ends here, of course, but you should get the idea.
Should I turn this into a proposal?

Seems like a nifty idea to me. Loose ends include:
- This obviously is redundant with Unified Function Call Syntax, in case that idea isn't totally dead yet.
- I encourage you to find some alternative syntaxes to that dangling "=" sign. Even if it doesn't confuse the grammar, it's confusing to me as a reader.
- When is the temporary *this constructed, and when is it destroyed? (This might be obvious; I'm not sure.)
- Virtual functions mustn't be by-value.
- Member functions of abstract classes mustn't be by-value.
- What would it mean to mark a member function by-value *and* const? Is the const qualifier ignored in that case?
- By-value member functions presumably shouldn't be allowed to call non-by-value member functions, is that right?

Arguably, the entire idea is a bad one. You're proposing that I be allowed to write a method call

    myobj.mymethod();

where the code inside mymethod does not interact with the object named myobj at all!  This feels like a horrible subversion of traditional OO practice... and after all, "traditional OO practice" is the only reason C++ supports member functions to begin with. (Otherwise we'd all use free functions all the time. The STL is only lately catching up to the free-function bandwagon with templates like std::begin and std::size, but I don't doubt it'll get there eventually.)
Now, I'm not saying that I personally feel strongly in that direction. But I'm sure a fair number of people do, so your proposal should explain the complaint and then figure out a defense against it.

–Arthur

Thiago Macieira

unread,
Mar 24, 2017, 9:13:18 PM3/24/17
to std-pr...@isocpp.org
On sexta-feira, 24 de março de 2017 15:35:09 PDT Arthur O'Dwyer wrote:
> Seems like a nifty idea to me. Loose ends include:
> - This obviously is redundant with Unified Function Call Syntax, in case
> that idea isn't totally dead yet.

True, but it seems it is dead...

> - I encourage you to find some alternative syntaxes to that dangling "="
> sign. Even if it doesn't confuse the grammar, it's confusing to me as a
> reader.

And clashes with "= 0" for pure virtuals. Even though passing a polymorphic
type by value is probably a bad idea, someone may want it.

> - When is the temporary *this constructed, and when is it destroyed? (This
> might be obvious; I'm not sure.)

I'd expect the same rules as if it were an implicit parameter, which is the
same as the Unified Function Call syntax.

> - Virtual functions mustn't be by-value.
> - Member functions of abstract classes mustn't be by-value.

To both: Why not? Sure, it's a bad idea, but any strict reason why not?

> - What would it mean to mark a member function by-value *and* const? Is the
> const qualifier ignored in that case?

It's indeed redundant, since you're clearly not modifying the original. But
having that "const" there can help the eyes.

Another question: what should *this be in that function? Should it be const or
not?

> - By-value member functions presumably shouldn't be allowed to call
> non-by-value member functions, is that right?

I don't see why. They can call, but the object modified is obviously the copy,
not the original.

> *Arguably*, the entire idea is a bad one. You're proposing that I be
> allowed to write a method call
>
> myobj.mymethod();
>
> where the code inside mymethod does not interact with the object named
> myobj at all! This feels like a horrible subversion of traditional OO
> practice... and after all, "traditional OO practice" is the only reason C++
> supports member functions to begin with. (Otherwise we'd all use free
> functions all the time. The STL is only lately catching up to the
> free-function bandwagon with templates like std::begin and std::size, but I
> don't doubt it'll get there eventually.)

Well, it did interact with myobj, when you created a copy.

The point is that most const member functions will not modify the object, so
it hardly matters to them if they receive a pointer to the original or if it's
an identical copy. But it does matter for performance and code optimisation:
passing by value in registers is more efficient, plus the compiler knows for a
fact the original was not modified, so it can optimise the code that follows on
that assumption.

> Now, I'm not saying that I personally feel *strongly* in that direction.
> But I'm sure a fair number of people do, so your proposal should explain
> the complaint and then figure out a defense against it.

--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
Software Architect - Intel Open Source Technology Center

Reply all
Reply to author
Forward
0 new messages