移动构造函数和std :: move混淆

时间:2014-12-16 05:02:56

标签: c++ c++11 move rvalue-reference

我正在阅读std::move,移动构造函数和移动赋值运算符。 说实话,我现在得到的只是困惑。现在我有一个班级:

class A{
  public:
    int key;
    int value;
    A(){key = 3; value = 4;}
    //Simple move constructor
    A(A&& B){ A.key = std::move(B.key); 
              A.value = std::move(B.value);}
};
  1. 我认为B是左值参考,为什么你可以将std::move应用于ravlue参考的成员?
  2. 移动B.keyB.value后,两者都已失效,但作为班级B的对象的A如何失效?
  3. 如果我有A a(A())A()显然是一个rvlaue,A()可以std::move移动,为什么会这样?
  4. 同样,如果我有一个功能

    int add(int && z){ int x = std:move(z); int y = std:move(z); return x+y; }

  5. 如果我致电add(5)该怎么办?5如何移动?为什么? 请注意,z已被移动两次,在第一次移动z后,它已被无效,您又如何移动它?

    1. 定义foo (T && Z )T时,Z可以是任何内容),在定义的正文中为什么我应该使用std::move(Z) Z已经通过右值引用传递,何时应该使用std::move

2 个答案:

答案 0 :(得分:11)

你必须明白std::move不会移动任何东西,但是“标记”它的参数是一个右值引用。从技术上讲,它将类型转换为右值引用。然后,rvalue引用它被相应的移动构造函数或移动赋值运算符移动。对于仅包含具有普通移动ctors /赋值运算符的成员的对象,移动ctor /赋值运算符是微不足道的,只需复制。通常,对象的move ctor / assignment运算符调用其所有成员的move ctor / assignment运算符。

所以,每当你写

int x = 10;
int y = std::move(x); 

在作业y = std::move(x)的右侧,您有一个类型为int&&的右值引用。但是,int没有非平凡的移动ctor,并且rvalue只是复制到yx中没有任何更改。

另一方面,

string s = "some string";
string moved_s = std::move(s); // here we tell the compiler that we can "steal" the resource of s

是不同的。 moved_s的移动构造函数启动,并且“窃取”(即交换内部指针等)s的资源,因为后者是右值引用。最后,s将不包含任何元素。

答案 1 :(得分:1)

  1. B是对象的名称。绑定引用后,它会命名一个对象。区别"右值参考","左值参考"和"命名对象"仅适用于在你走到这一步之前如何绑定名称。
  2. B.key是对象中变量的名称,该变量作为此函数调用的参数提供。

    1. "无效"不属于移动的标准术语的一部分。移出后,标准库对象保留在未指定的状态;但这不是在这里发生的事情。
    2. A.key = std::move(B.key)调用int的内置赋值定义(这是一个简单的赋值,而不是函数调用),它只是一个副本。所以B.key保留了它的价值。

      1. A(B())进行编译,B必须是您尚未定义的类型名称。 (您的意思是A(A())吗?如果是,那么答案是"是")。

      2. 见2

      3. 当您想要离开std::move(Z.foo)而不是从Z.foo复制时,请使用Z.foo