为什么C ++左值对象不能绑定到右值引用(&&)?

时间:2016-02-26 13:26:07

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

移动语义的想法是,您可以从另一个临时对象(由右值引用引用)中获取所有内容,并将“所有内容”存储在对象中。这有助于避免在单个构造事物足够的情况下进行深度复制 - 因此,您可以在右对象中构造事物,然后将其移动到长寿命对象中。

为什么C ++不允许将左值对象绑定到右值引用?两者都允许我更改引用的对象,因此在访问引用对象的内部方面对我没有任何区别。

我能猜到的唯一原因是函数重载模糊问题。

2 个答案:

答案 0 :(得分:21)

  

但是为什么C ++不允许将左值对象绑定到右值引用?

假设你的意思是“为什么C ++不允许绑定对左值对象的rvalue引用”:它确实如此。它不是自动的,因此您必须使用std::move使其明确。

为什么呢?因为否则一个无害的函数调用会令人惊讶地破坏你没想到的东西:

Class object(much,state,many,members,wow);
looks_safe_to_me(object);
// oh no, it destructively copied my object!

VS

Class object(much,state,many,members,wow);
obviously_destructive(std::move(object));
// same result, but now the destruction is explicit and expected

关于破坏性复制的说明:为什么我说上面的破坏性销毁,我并不是说对象析构函数结束了它的生命周期:只是它的内部状态已经存在移动到新实例。它仍然是一个有效的对象,但不再具有以前相同的昂贵状态。

关于术语的说明:让我们看看我们是否可以清除上面左值 rvalue 等的不精确使用。

cppreference引用后代:

  • lvalue

      

    无法从移动具有身份的表达式。

    所以,没有lvalue对象这样的东西,但是有一个由左值表达式本地命名(或引用)的对象

  • rvalue

      

    表达式,它是prvalue或xvalue。它可以从移动。它可能有也可能没有身份。

    • prvalue (纯rvalue)大致是指未命名的临时对象的表达式:我们无法将左值表达式转换为这些IIUC中的一个。

    • xvalue (到期值)

        

      可以从移动具有身份的表达式。

      明确包含std::move

    • 的结果

实际发生了什么:

  • 存在对象
  • 通过左值表达式在本地识别对象,该表达式无法移动(以保护我们免受意外的副作用)
  • std::move产生一个xvalue表达式(可以从中移动)引用与左值表达式相同的对象
  • 这意味着诸如变量(由左值表达式命名)之类的对象不能被隐式地移动,而必须通过显式xvalue表达式来显式显式地移动,例如std::move
  • 匿名临时表可能已经由prvalue表达式引用,并且可以隐式移动

答案 1 :(得分:4)

基本上,需要一种机制来区分可以移动的值和不能移动的值(即需要复制)。

允许rvalues和lvalues绑定到左值引用使得这不可能。

因此,绑定到右值引用的值可以从(不一定总是要移动,但允许)移动,并且左值可以绑定到左值引用,并且不能从中移动。

std::move允许在值类别(到右值)之间进行转换以允许移动发生。

请注意; const左值引用(const T&)可以绑定到rvalues(临时值)和左值,因为引用的对象不能更改(它被标记为const所以无论如何都不能有任何移动)。

有一些历史(早在C ++的早期)为什么临时对象无法绑定到非const左值引用开始... ...细节模糊但有一些推理修改临时didn't make sense,因为无论如何它会在当前声明的最后破坏。另外,当你实际上没有修改左值时,你可能会感觉到你正在修改左值 - 代码的语义可能/将是错误的并且是错误的。 There are further reasons与地址,文字等相关联。这是在移动之前,其语义固化,并且是移动及其语义的一些动机。