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.