It depends on the compiler. In this case, the standard requires that there will be at least one constructor call. Namely, the construction of t
.
But the standard allows the possibility of two others: the move-construction of the value output of foo
from t
, and the move-construction of s
from the value output of foo
. Most decent compilers will forgo these constructors by constructing t
directly in the memory for s
. This optimization is made possible because the standard allows these constructors to not be called if the compiler chooses not to.
This is called copy/move "elision".
If so, in the function I am not even returning rvalue reference, so how could the compiler invoke the move constructor?
You seem to be laboring under the misconception that &&
means "move", and that if there's no &&
somewhere, then movement can't happen. Or that move construction requires move
, which also is not true.
C++ is specified in such a way that certain kinds of expressions in certain places are considered valid to move from. This means that the value or reference will attempt to bind to a &&
parameter before binding to a &
parameter. Temporaries, for example, will preferentially bind to a &&
parameter before a const&
one. That's why temporaries used to construct values of that type will be moved from.
If you have a function which returns a value of some type T
, and a return expression is of the form return x
, where x
is a named variable of type T
of automatic storage duration (ie: a function parameter or stack variable), then the standard requires that this return expression move construct the returned value from x
.
The return value of foo
is a temporary. The rules of C++ require that temporaries bind to &&
parameters before const&
. So you get move construction into s
.