简体   繁体   中英

Why std::move is required to invoke move assign operator of std::vector

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.

The expression a is an lvalue. The expression std::move(a) is an rvalue. Only rvalues bind to rvalue references, which make up the move constructor and move assignment operator.

It is worth repeating this to yourself until it makes sense: Evaluating any reference variable, and also dereferencing any dereferenceable pointer, produces an lvalue.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM