I'm trying to understand rvalue references and move semantics of C++11.
What is the difference between these examples, and which of them is going to do no vector copy?
First example:
std::vector<int> return_vector(void)
{
std::vector<int> tmp {1,2,3,4,5};
return tmp;
}
std::vector<int> &&rval_ref = return_vector();
Second example:
std::vector<int>&& return_vector(void)
{
std::vector<int> tmp {1,2,3,4,5};
return std::move(tmp);
}
std::vector<int> &&rval_ref = return_vector();
Third example:
std::vector<int> return_vector(void)
{
std::vector<int> tmp {1,2,3,4,5};
return std::move(tmp);
}
std::vector<int> &&rval_ref = return_vector();
First example
The first example returns a temporary which is caught by
rval_ref
. That temporary will have its life extended beyond therval_ref
definition and you can use it as if you had caught it by value. This is very similar to the following:except that in my rewrite you obviously can't use
rval_ref
in a non-const manner.Second example
In the second example you have created a run time error.
rval_ref
now holds a reference to the destructedtmp
inside the function. With any luck, this code would immediately crash.Third example
Your third example is roughly equivalent to your first. The
std::move
ontmp
is unnecessary and can actually be a performance pessimization as it will inhibit return value optimization.The best way to code what you're doing is:
Best practice
I.e. just as you would in C++03.
tmp
is implicitly treated as an rvalue in the return statement. It will either be returned via return-value-optimization (no copy, no move), or if the compiler decides it can not perform RVO, then it will use vector's move constructor to do the return. Only if RVO is not performed, and if the returned type did not have a move constructor would the copy constructor be used for the return.