我正在学习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;
}
结果是:
size of a before move: 3 size of a after move: 3
似乎在函数v = a
中的aaa
行未调用std :: vector的move assign运算符,否则a
的大小为0而不是3。
但是,如果我将v = a
更改为v = std::move(a)
,则输出变为
前移动的大小:3
后移动的大小:0
我瘦了这次调用了std :: vector的move赋值运算符。
我的问题是为什么第一次不调用assign运算符?根据c ++参考,std :: vector有一个赋值运算符,它接受一个右值引用。
copy(1)vector&amp; operator =(const vector&amp; x);
移动(2)矢量&amp; operator =( vector&amp;&amp; x );
初始化列表(3)向量&amp; operator =(initializer_list il);
然后在第v = a
行,因为a被声明为rvalue引用,所以应该调用move运算符。为什么我们仍然需要用std :: move包装一个?
非常感谢提前!
[编辑] 我认为Loopunroller和Kerrek SB都回答了我的问题。谢谢! 我不认为我可以选择两个答案,所以我会选择第一个答案。
答案 0 :(得分:10)
[expr] / 6的这一说明可能会澄清正在发生的事情(强调我的):
[注意:表达式是xvalue,如果它是:
- 调用函数的结果,无论是隐式还是显式,其返回类型是对象类型的右值引用,
- 强制转换为对象类型的右值引用,
- 一个类成员访问表达式,指定非引用类型的非静态数据成员,其中对象表达式是 xvalue或
.*
指向成员的表达式,其中第一个操作数是xvalue,第二个操作数是指向数据成员的指针。
通常,此规则的效果是名为rvalue的引用 被视为左值和对象的未命名右值引用 被视为xvalues;对函数的右值引用被视为 左值是否命名。 - 结束记录]
根据上面的列表(项目符号1),不难看出表达式std::move(a)
是x值。
a
是右值引用的名称,因此是左值作为表达。
答案 1 :(得分:6)
表达式a
是左值。表达式std::move(a)
是一个右值。只有rvalues绑定到rvalue引用,它构成了move构造函数和移动赋值运算符。
值得重复一遍,直到它有意义:评估任何引用变量,并且还取消引用任何可解除引用的指针,产生左值。