C++11 rvalues and move semantics confusion (return statement)
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();
The first example returns a temporary which is caught by rval_ref
. That temporary will have its life extended beyond the rval_ref
definition and you can use it as if you had caught it by value. This is very similar to the following:
const std::vector<int>& rval_ref = return_vector();
except that in my rewrite you obviously can't use rval_ref
in a non-const manner.
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();
In the second example you have created a run time error. rval_ref
now holds a reference to the destructed tmp
inside the function. With any luck, this code would immediately crash.
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();
Your third example is roughly equivalent to your first. The std::move
on tmp
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
std::vector<int> return_vector(void)
{
std::vector<int> tmp {1,2,3,4,5};
return tmp;
}
std::vector<int> rval_ref = return_vector();
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.
c++11 Return value optimization or move? [duplicate]
Use exclusively the first method:
Foo f()
{
Foo result;
mangle(result);
return result;
}
This will already allow the use of the move constructor, if one is available. In fact, a local variable can bind to an rvalue reference in a return
statement precisely when copy elision is allowed.
Your second version actively prohibits copy elision. The first version is universally better.
move semantics in constructor in return statement
This one is more efficient:
std::pair<std::vector<double>,std::vector<double> > some_func() {
std::vector<double> my_vec_a;
std::vector<double> my_vec_b;
//do something
return std::make_pair(std::move(my_vec_a),std::move(my_vec_b));
}
without the calls to std::move
the two vectors will be copied.
The problem, however, isn't the actual return. It's that the two vectors in the pair being constructed are being constructed from lvalues; the compiler can't choose to use a move-constructor there without you explicitly telling it to via std::move
.
move constructor called on return instead of copy
From cppreference (emphasis mine):
If [the returned expression] is an lvalue expression and the conditions for copy elision are met, or would be met, except that [the returned expression] names a function parameter, then overload resolution to select the constructor to use for initialization of the returned value is performed twice: first as if [the returned expression] were an rvalue expression (thus it may select the move constructor or a copy constructor taking reference to const), and if no suitable conversion is available, overload resolution is performed the second time, with lvalue [returned expression] (so it may select the copy constructor taking a reference to non-const).
The above rule applies even if the function return type is different from the type of [the returned expression] (copy elision requires same type)
Long story short, return
implicitly tries to move what you return when it makes sense. It will only copy as a last resort (no move constructor available, for example).
Why is using the move constructor in a return statement legal?
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.
Related Topics
How to Determine Opencv Version
How to Have All the Inputs on the Same Line C++
Opencv Imread(Filename) Fails in Debug Mode When Using Release Libraries
Fastest Way to Check If a File Exists Using Standard C++/C++11,14,17/C
How to Align Text to the Right Using Cout
Checking the Neighbour Values of Arrays
How to Read in User Entered Comma Separated Integers
Balanced Array Index While Summing an Array from Left and Right
How to Cast Const Uint8_T* to Char*
How to Determine the Boost Version on a System
How to Properly Clean Up Elements from Vectors of Object Pointers
Automatically Add All Files in a Folder to a Target Using Cmake
When Should You Use a Class VS a Struct in C++