为什么需要std :: move来调用std :: vector的move assign运算符

Son*_*ong 6 c++ stdvector rvalue-reference move-semantics c++11

我正在学习c ++ 11,我对移动语义和右值引用有疑问.我的示例代码如下(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;
}
Run Code Online (Sandbox Code Playgroud)

结果是:

size of a before move: 3  
size of a after move: 3
Run Code Online (Sandbox Code Playgroud)

这似乎性病::向量的线,则不会调用的移动赋值运算符v = a的功能aaa,否则a将有大小为0,而不是3.
但是,如果我改变v = av = std::move(a)输出成为

前移动的
大小:后移动的3个大小:0

我瘦了这次调用std :: vector的move赋值运算符.

我的问题是为什么第一次不调用assign运算符?根据c ++参考,std :: vector有一个赋值运算符,它接受一个右值引用.

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

然后在行v = a,因为a被声明为rvalue引用,所以应该调用move运算符.为什么我们仍然需要使用std :: move包装?

提前谢谢了!

[编辑]我认为Loopunroller和Kerrek SB都回答了我的问题.谢谢!我不认为我可以选择两个答案,所以我会选择第一个答案.

Col*_*mbo 11

[expr]/6中的这一说明可能会澄清正在发生的事情(强调我的):

[ 注意:表达式是xvalue,如果它是:

  • 调用函数的结果,无论是隐式还是显式,其返回类型是对象类型的右值引用,
  • 强制转换为对象类型的右值引用,
  • 一个类成员访问表达式,指定非引用类型的非静态数据成员,其中对象表达式是xvalue,或者
  • 一个.*指针到构件表达,其中第一操作数是一个x值和第二个操作数是一个指向数据成员.

通常,此规则的作用是将命名的右值引用视为左值,将对象的未命名右值引用视为xvalues; 对函数的右值引用被视为左值,无论是否命名.- 结束说明 ]

std::move(a)根据上面的列表(第一项),不难看出表达式是xvalue.
a是左值引用的名称,因此是左值作为表达式.


Ker*_* SB 8

表达式a是左值.表达式std::move(a)是一个右值.只有rvalues绑定到rvalue引用,它们组成了移动构造函数和移动赋值运算符.

值得重复这一点直到它有意义:评估任何引用变量,并且还取消引用任何可解除引用的指针,产生左值.

  • 重要的一点是为什么这条规则就是这样.当他调用`a = v`时,编译器无法知道他不再需要`v`(事实上,他之后会使用它),因此除非你特别授权,否则它不会冒险改变它的风险至. (3认同)