I am learning c++11 and i have a question regarding move semantics and rvalue references. My sample code is as following (C++ Shell URL is cpp.sh/8gt):
#include <iostream>
#include <vector>
void aaa(std::vector<int>&& a)
{
std::cout << "size of a before move: " << a.size() << std::endl;
std::vector<int> v;
v = a; /*std::move(a)*/
std::cout << "size of a after move: " << a.size() << std::endl;
}
int main ()
{
std::vector<int> foo (3,0);
aaa(std::move(foo));
return 0;
}
The result of the is:
size of a before move: 3 size of a after move: 3
It seems the move assign operator of std::vector is not invoked at line v = a
in function aaa
, otherwise a
would have size 0 instead of 3.
However if i change v = a
to v = std::move(a)
the output became
size of a before move: 3
size of a after move: 0
and I thinke the move assign operator of std::vector has been invoked this time.
My quesiton is why the assign operator is not invoked the first time? According to c++ reference std::vector has a assign operator which takes a rvalue reference.
copy (1) vector& operator= (const vector& x);
move (2) vector& operator= (vector&& x);
initializer list (3) vector& operator= (initializer_list il);
Then at line v = a
, since a is declared as rvalue reference, the move operator should be invoked. Why we still need to wrap a with a std::move?
Many thanks in advance!
[edit] I think both Loopunroller and Kerrek SB answered my question. Thanks! I don't think I can choose two answers so I will just pick the first one.
This note from [expr]/6 might clarify what is going on (emphasis mine):
[ Note: An expression is an xvalue if it is:
- the result of calling a function, whether implicitly or explicitly, whose return type is an rvalue reference to object type,
- a cast to an rvalue reference to object type,
- a class member access expression designating a non-static data member of non-reference type in which the object expression is an xvalue, or
- a
.*
pointer-to-member expression in which the first operand is an xvalue and the second operand is a pointer to data member.
In general, the effect of this rule is that named rvalue references are treated as lvalues and unnamed rvalue references to objects are treated as xvalues; rvalue references to functions are treated as lvalues whether named or not. — end note ]
It is not hard to see that the expression std::move(a)
is an xvalue according to the list above (bullet one).a
is the name of an rvalue reference, and thus an lvalue as an expression.
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