Consider the following:
#include
#define trace(name) std::cout << #name << \" (\" << this << \"), i = \" << i
When move semantics where added to C++ in C++11, decisions where made about where to automatically do move construction.
The general rule that was followed was that implicit move should occur when copy elision would be legal.
Copy elision is legal when you have an anonymous object that you are copying to another instance. The compiler can legally elide the copy, and treat the two objects as one, with a lifetime equal to the union of the two objects lifetime.
The other time that copy elision is legal is when you return a local variable from a function. This was known as NRVO (named return value optimization). This optimization in C++03 let you declare a return value, and it is constructed directly in the place where the return value goes. When you return retval;
, no copy happens.
This is basically impossible to do without inlining when you return multiple different objects at different spots in your function.
However, when move semantics where added, this place was the other spot where implicit move can occur. A return local_var;
in a function returning a variable the same type as local_var
can be elided, and failing that, you can implicitly move from local_var
into the return value.
C++11 12.8/32: When the criteria for elision of a copy operation are met or would be met save for the fact that the source object is a function parameter, and the object to be copied is designated by an lvalue, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue.
Returning a local automatic variable meets the criteria for elision; treating it as if it were an rvalue selects the move constructor.