The compilers are permitted to any and all code transformations that do not change the observable behavior of the program, by applying the as-if rule.
However, copy_elision is an exception from the as-if rule: the compiler may remove calls to move- and copy-constructors and the matching calls to the destructors of temporary objects even if those calls have observable side effects. To witness these side effects, you have to use -fno-elide-constructors
option while compiling.
From the copy_elision page, we should look at the clause:
In a return statement, when the operand is the name of a non-volatile
object with automatic storage duration, which isn't a function
parameter or a catch clause parameter, and which is of the same class
type (ignoring cv-qualification) as the function return type. This
variant of copy elision is known as NRVO, "named return value
optimization".
When the compiler sees the below structure, it knows it is a candidate for NRVO.
T FunctionName ( ... )
{
T a;
...
return a;
}
Which matches the code structure of your problem.
std::vector<T> foo() {
std::vector<T> result;
// populate result
{
/*
for loop with result.push_back().
ignore real code.
*/
}
return result;
}
Case 1 -
const auto v = foo(); <-- will it move the vector by default?
What you are witnessing is not move-semantics, it is just NRVO.
So the question doesn't have any relevance here.
Case 2 -
const auto &v = foo(); <-- same question as above, assuming T is movable
It doesn't matter if T
is movable. There is no move
happening here.
The concept that is taking place is const &
can bind to a temporary.
We would achieve the same result in pre-C++11 compiler as well, which didn't have move-semantics support.