Reputation: 21475
Consider the foo
function
void foo(X x);
with X
a matrix cass, and the function
X foobar();
Suppose that I run
foo(foobar());
What happens with temporary objects in this case step by step? My understanding is that
foobar
returns a temporary object, say Xtemp1
;foo
copies Xtemp1
to a temporary object of its own, say Xtemp2
, and then destroyes Xtemp1
;foo
performs calculations on Xtemp2
.On the other side, if I overload foo
as
void foo(X& x);
void foo(X&& x);
then the picture will be different and, in particular,
foobar
returns the temporary Xtemp1
;foo
does not create a new temporary, but acts directly on Xtemp1
through its reference.Is this picture correct or, if not, could someone point out and fix my mistakes? Thank you very much.
Upvotes: 2
Views: 364
Reputation: 473437
foo(foobar());
foobar
's return value is a value, so it's a temporary value.foo
.foo
executes.foo
returns, it's parameter is destructed.foo
returns, the value in local storage is destructed.foobar
's return value is destructed.1 These moves/copies may be elided by the compiler. This means that these copy/moves don't have to happen (and any compiler worth using will elide them).
2 If the moves/copies above are elided, then the destruction of their respective variables are naturally unnecessary. Since they don't exist.
On the other side, if I overload foo as
foobar
's return value is a value, so it's a temporary value.foo(X &&)
to call.foo
executes.foo
returns, it's reference parameter is destructed (not the value it references).foo
returns, the value in local storage is destructed.foobar
's return value is destructed.Note the key differences here. Step 4 and 6 cannot be elided. Therefore, if X
is a small type like int
, then the function will have no choice but to create a fairly worthless reference to an integer. References are internally implemented as pointers, so it's not really possible for the compiler to just optimize that away as a register. The local storage must therefore be on the stack rather than a register.
So you will be guaranteed of fewer move/copies. But again, any decent compiler will elide them. So the question is, will X
generally be too large to fit into a register?
Upvotes: 2
Reputation: 171127
Your understanding is almost correct. The only difference is that in step 2., the temporary Xtemp1
is not copied to an arbitrary-named temporary Xtemp2
, but to the space of the formal parameter x
(from declaration foo(X x)
).
Also, it's possible for copy-elision to kick in, which could mean that the return value of foobar()
is constructed directly in the space of foo
's formal parameter x
, thus no copying would occur. This is allowed by the standard, but not guaranteed.
Your take on the r-value reference case is correct.
Upvotes: 1