As I am learning C++11 rvalue references and move semantics, I start to feel confused about exactly how function returns a value to initialize a variable. Look at the following example:
Widget makeWidget()
{
Widget w;
…
return w;
}
Widget w1 = makeWidget();
Here I assume no RVO (i.e., the compile won't elide copy/move). When executing the return statement return w;
, does the function:
1) copy initialize a temporary object, whose value becomes the function's return value, in a well known location (some fixed register or memory location that caller knows)? Then caller fetches this object to copy initialize w1
? Or
2) the function gets the caller-passed memory location of w1
and the function's automatic variable w
is used to copy initialize w1
? (Is this some sort of RVO already? Or some sort of inline function behavior? Or it is a possible calling convention?)
If it is the first case, and return creates a temporary, there would be two copy constructor calls, one creating the temporary, one creating w1
. If it is the second case, there would be only one copy constructor call to create w1
.
Now assume we have RVO. Then if the behavior of return is case 1), then compiler can elide the copy construction of the temporary, by constructing w
directly in the well known location for return value. If return behaves like case 2), then RVO, in this case, can even create automatic variable w
directly in the memory location allocated for w1
. Is my understanding for RVO correct?
Now let me add move semantics in. Assume again, there is no RVO, and look at the following example:
Widget makeWidget()
{
Widget w;
…
return std::move(w);
}
Widget w1 = makeWidget();
Now again for the two cases above:
1) do I expect two moves: first move comes from initializing the temp Widget
object with expression std::move(w)
; second move comes from initializing w1
with the temp Widget
which is a rvalue? OR
2) there is only one move: initializing w1
with the expression std::move(w)
?
Final question: does the return behavior depend on whether it returns a POD type or a class type?
1) copy initialize a temporary object, whose value becomes the function's return value, in a well known location (some fixed register or memory location that caller knows)? Then caller fetches this object to copy initialize w1?
Roughly this. Usually, the caller allocates the necessary stack space to hold the return value and pass a pointer to it as a hidden argument.
Note that both copy-initializations are actually moves.
then compiler can elide the [...] construction of the temporary, by constructing
w
directly in the well known location for return value.
Right (but it's a move). And it can further elide the construction of w1
by passing its address as the location at which the return value should be constructed.
Widget makeWidget() { Widget w; … return std::move(w); } Widget w1 = makeWidget();
This is one non-elidable move (from std::move(w)
to the temporary return value) and one elidable move (from the temporary return value to w1
).
does the return behavior depend on whether it returns a POD type or a class type?
It can. Depending on the platform ABI, some small POD types may be returned in registers.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With