移动语义的想法是,您可以从另一个临时对象(由右值引用引用)中获取所有内容,并将“所有内容”存储在对象中。这有助于避免在单个构造事物足够的情况下进行深度复制 - 因此,您可以在右对象中构造事物,然后将其移动到长寿命对象中。
为什么C ++不允许将左值对象绑定到右值引用?两者都允许我更改引用的对象,因此在访问引用对象的内部方面对我没有任何区别。
我能猜到的唯一原因是函数重载模糊问题。
答案 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对象这样的东西,但是有一个由左值表达式本地命名(或引用)的对象
表达式,它是prvalue或xvalue。它可以从移动。它可能有也可能没有身份。
prvalue (纯rvalue)大致是指未命名的临时对象的表达式:我们无法将左值表达式转换为这些IIUC中的一个。
xvalue (到期值)
可以从移动具有身份和的表达式。
明确包含std::move
实际发生了什么:
std::move
产生一个xvalue表达式(可以从中移动)引用与左值表达式相同的对象std::move
。答案 1 :(得分:4)
基本上,需要一种机制来区分可以移动的值和不能移动的值(即需要复制)。
允许rvalues和lvalues绑定到左值引用使得这不可能。
因此,绑定到右值引用的值可以从(不一定总是要移动,但允许)移动,并且左值可以绑定到左值引用,并且不能从中移动。
std::move
允许在值类别(到右值)之间进行转换以允许移动发生。
请注意; const左值引用(const T&
)可以绑定到rvalues(临时值)和左值,因为引用的对象不能更改(它被标记为const
所以无论如何都不能有任何移动)。
有一些历史(早在C ++的早期)为什么临时对象无法绑定到非const左值引用开始... ...细节模糊但有一些推理修改临时didn't make sense,因为无论如何它会在当前声明的最后破坏。另外,当你实际上没有修改左值时,你可能会感觉到你正在修改左值 - 代码的语义可能/将是错误的并且是错误的。 There are further reasons与地址,文字等相关联。这是在移动之前,其语义固化,并且是移动及其语义的一些动机。