为什么C++左值对象不能绑定到右值引用 (&&)?
Why C++ lvalue objects can't be bound to rvalue references (&&)?
移动语义的思想是,您可以从另一个临时对象(由右值引用引用)中获取所有内容,并将该"所有内容"存储在对象中。这有助于避免深度复制,因为单个事物的构造就足够了 - 因此您可以在右值对象中构造事物,然后将其移动到长期存在的对象中。
为什么C++不允许将左值对象绑定到右值引用?两者都允许我更改引用的对象,因此在访问引用对象的内部方面对我来说没有区别。
我能猜到的唯一原因是函数重载歧义问题。
但是为什么C++不允许将左值对象绑定到右值引用呢?
假设你的意思是"为什么C++不允许将右值引用绑定到左值对象":确实如此。它只是不是自动的,因此您必须使用std::move
来使其明确。
为什么?因为否则,无害的函数调用可能会令人惊讶地破坏您意想不到的东西:
Class object(much,state,many,members,wow);
looks_safe_to_me(object);
// oh no, it destructively copied my object!
与。
Class object(much,state,many,members,wow);
obviously_destructive(std::move(object));
// same result, but now the destruction is explicit and expected
关于破坏性复制的说明:为什么我在上面说破坏性和破坏,我并不是说对象析构函数结束了它的生命周期:只是它的内部状态已经移动到一个新的实例。它仍然是一个有效的对象,但不再具有与以前相同的昂贵状态。
关于术语的说明:让我们看看是否可以清除上面左值、右值等的不精确使用。
引用后人的话:
左值是
因此,没有左值对象具有标识且无法从中移动的表达式。
这样的东西,但是有一个对象由左值表达式在本地命名(或引用)
右值是
作为 PR值或 XValue 的表达式。它可以从中移动。它可能具有也可能没有标识。
prvalue(纯右值)大致是一个引用未命名临时对象的表达式:我们不能将我们的 lvalue 表达式转换为这些 IIUC 之一。
x值(即将过期的值)为
具有标识且可从中移动的表达式。
明确包括
std::move
的结果
那么实际发生了什么:
- 对象存在
- 该对象由左值表达式在本地标识,该表达式无法移动(以保护我们免受意外的副作用)
-
std::move
生成一个 xvalue 表达式(可以从中移动),引用与 lvalue 表达式相同的对象 - 这意味着诸如变量(由 lvalue 表达式命名)之类的对象不能隐式移动,而必须通过显式 xvalue 表达式(如
std::move
)显式移动。 - 匿名临时可能已经被 prvalue 表达式引用,并且可以隐式移动
本质上,需要一种机制来区分可以从中移动的值和无法移动的值(即需要副本)。
允许右值和左值都绑定到左值引用使这是不可能的。
因此,绑定到右值引用的值可以从中移动(不一定总是从中移动,但这是允许的),并且左值可以绑定到左值引用,但不能从中移动。
std::move
允许在值类别(到右值)之间进行转换以允许移动发生。
注意;常量左值引用(const T&
)可以绑定到右值(临时)和左值,因为引用的对象不能更改(它被标记为const
因此无论如何都不能有任何移动)。
有一些历史(可以追溯到 C++ 的早期)为什么临时对象不能绑定到非常量左值引用......细节很模糊,但有一些理由认为修改临时没有意义,因为它无论如何都会在当前语句的末尾破坏。此外,您可能会被哄骗到您正在修改左值的感觉中,而实际上并非如此 - 代码的语义可能/将是错误的并且有问题。还有其他原因与地址、文字等有关。这是在移动之前,其语义固化,并且是移动及其语义的一些动机。
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- 将常量指针引用绑定到非常量指针
- 运行时错误:引用绑定到类型为"int"的空指针
- 模板允许左值与右值引用绑定
- 运行时错误:引用绑定到类型"int"的未对齐地址0xbebebebebebebec6,这需要 4 个字节对齐 (stl_vector.h)
- 无法将类型"T&"的非常量左值引用绑定到类型"T"的右值 t++ std::atomic<T>
- 为什么定义复制构造函数会给我错误:无法将类型 'obj&' 的非常量左值引用绑定到类型为"obj"的右值?
- 将引用绑定到指针的语法是什么?(各种)
- 为什么我不能将常量左值引用绑定到返回 T&&&的函数?
- 为什么 VS 无法将右值引用绑定到指针?
- 出于什么原因,有必要将常量左值引用绑定到右值?
- 为什么此右值引用绑定到左值?
- 使用“void*”将右值引用绑定到左值
- 排序时引用绑定到 'value_type' 类型的 null 指针
- 无法将类型为"类名 &"的非常量左值引用绑定到类型为"类名"的右值
- 引用绑定和复制构造函数/移动构造函数
- 将引用绑定到类型的值会删除限定符 MULTISET
- 无法将类型"int&"的非常量左值引用绑定到类型为"int"的右值
- 多态变体,并将一种类型的引用绑定到另一种类型的引用
- C++17:是编译器为(静态存储持续时间)const引用绑定创建的可修改的临时对象(和存储)