I know that in c++11 the move semantics have been implemented in the STL containers to avoid temporary objects. And people say that now it's perfect to write functions which return by value. But I have some confusions about on earth how many times of copying are actually get avoided. Please see the following example:
vector<int> myVector() {
vector<int> res;
res.push_back(4);
res.push_back(5);
return res;
}
vector<int> v = myVector();
My understanding is that in c++03, myVector
returns a copy of res
( 4
, 5
copied once), when evaluating vector<int> v = myVector();
vector<int>
's copy constructor vector<int>(const vector<int> &)
is invoked ( 4
, 5
copied twice). However in c++11 with move semantics, I want to know which copy of 4
and 5
gets avoided? both? Is return value optimization also invoked to reduce one time of copying 4
and 5
?
There are two copies in C++03 and two moves in C++11.
In both C++03 and C++11 the copy/moves are subject to elision, and as such (in an example like this) no copy/move is likely to happen.
vector<int> myVector() {
vector<int> res;
res.push_back(4);
res.push_back(5);
return res;// <- Here we construct the return value with res
}
// here we construct v with the return value of myVector:
vector<int> v = myVector();
The elision out of the res
into the return value of myVector
is somewhat fragile. In C++11, the move
that could occur if elision fails is going to be nearly as free (as doing nothing) -- 3 pointer copies, and 3 pointer clears. In C++03, the copy that could occur if elision fails can be expensive (memory allocation and O(n) copies).
Elision is the name of the operation compilers can do in certain circumstances where two values are turned into one, even if that transformation would cause a change in behavior (ie, it fails the as-if test).
When this happens, the combined value has a lifetime of the union of the two lifetimes.
In the above case, the local variable res
and the return value of myVector()
can be elided by the NRVO rule (named return value optimization). The return value of myVector
can be elided into v
as it is a statement of the form A a = b
where b
is an expression that results in an anonymous value (the name of such anonymous values has changed from C++03 to C++11 so I won't use it), in particular the return value of myVector()
.
This cause the lifetime of res
v
and the return value of myVector()
to be merged into one value lifetime. In practice, what happens is res
is placed directly into where the return value of myVector()
is supposed to go (according to the calling convention), and so is v
, and destruction is of this combined value skipped until v
goes out of scope, as is construction in the return
statement and on v = myVector()
.
Or in other words, v
is constructed directly in myVector
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With