Why is std :: move required to call the assignment operator of the std :: vector operator

I am learning C ++ 11, and I have a question regarding the semantics of movement and references to rvalue values. My sample code is as follows (C ++ shell URL 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; } 

Result:

 size of a before move: 3 size of a after move: 3 

It seems that the move assignment operator std :: vector is not called on the line v = a in the aaa function, otherwise a will be of size 0 instead of 3.
However, if I changed v = a to v = std::move(a) , the result is

size before moving: 3
size after movement: 0

and I think this time the destination assignment operator std :: vector was called.

My quesiton is why the assignment operator is not called for the first time? According to C ++, the std :: vector reference has an assignment operator that accepts an rvalue reference.

copy (1) vector & operator = (const vector & x); move (2) vector & operator = ( vector & x );
initializer list (3) vector & operator = (initializer_list il);

Then, in the string v = a , since a is declared as an rvalue reference, the move operator must be called. Why do we still need to wrap with std :: move?

Thank you very much in advance!

[edit] I think both Loopunroller and Kerrek SB answered my question. Thank you I donโ€™t think I can choose two answers, so Iโ€™ll just choose the first one.

+5
source share
2 answers

This note from [expr] / 6 can clarify what is happening (my attention):

[Note: an expression is an x โ€‹โ€‹value if it:

  • the result of a function call, implicitly or explicitly, whose return type is an rvalue reference to an object type,
  • link to rvalue link for object type,
  • class member access expression denoting a non-static data item of a non-reference type in which the object expression is xvalue, or
  • a .* pointer-to-member expression, in which the first operand is the value x, and the second operand is a pointer to a data element.

In general, the effect of this rule is that named rvalue references are treated as lvalues, and unnamed rvalue object references are treated as x values; rvalue function references are treated as lvalues, name or not. - final note]

It is easy to see that the expression std::move(a) is the value of x according to the list above (bullet one).
a is the name of the rvalue reference and therefore lvalue as an expression.

+9
source

The expression a is an lvalue. The expression std::move(a) is an r-value. Only rvalues โ€‹โ€‹bind to rvalue references that make up the move constructor and move the assignment operator.

It is worth repeating this for yourself until it makes sense: evaluating any reference variable, as well as dereferencing any dereferenced pointer, produces an lvalue.

+6
source

Source: https://habr.com/ru/post/1205373/


All Articles