led*_*ter 7 c++ xvalue c++14 prvalue value-categories
我对这个问题的广泛性感到抱歉,只是所有这些细节都是紧密相连的。
我一直在尝试理解两个特定值类别 - xvalues 和 prvalues 之间的区别,但我仍然感到困惑。
不管怎样,我试图为自己开发的“同一性”概念的心智模型是,应该保证具有同一性的表达式驻留在实际程序的数据存储器中。
由于这个原因,字符串文字是左值,它们保证在整个程序运行期间驻留在内存中,而数字文字是纯右值,并且可以假设存储在直接汇编中。
这似乎同样适用于std::move纯纯右值文字,即,在调用时,fun(1)我们只会在被调用者框架中获得参数左值,但在调用时,fun(std::move(1))左值的 xvalue“种类”必须保留在调用者框架中。
然而,这种心理模型至少不适用于临时对象,据我所知,临时对象应该始终在实际内存中创建(例如,如果像使用纯右值参数那样调用fun(MyClass())右值引用函数)。所以我认为这种思维模式是错误的。
那么,思考 xvalue 的“同一性”属性的正确方法是什么?我已经读过,通过身份我可以比较地址,但是如果我可以比较 2 的地址MyClass().member(根据 cppreference 的 xvalue),比方说通过右值引用将它们传递到某个比较函数中,那么我不明白为什么我可以不对 2 MyClass()s(纯右值)做同样的事情吗?
与此相关的另一个来源是此处的答案: 什么是移动语义?
请注意,尽管 std::move(a) 是右值,但其求值不会创建临时对象。这个难题迫使委员会引入第三个价值类别。可以绑定到右值引用的东西,即使它不是传统意义上的右值,也称为xvalue(到期值)。
但这似乎与“可以比较地址”无关,并且a)我不明白这与右值的“传统意义上”有什么不同;b) 我不明白为什么这样的原因需要语言中的新值类别(好吧,这允许为 OO 意义上的对象提供动态类型,但 xvalue 不仅仅指对象)。
bol*_*lov 14
我个人有另一种心理模型,它不直接处理身份和记忆等。
prvalue来自“纯右值”,而xvalue来自“过期值”,我在我的心理模型中使用的是以下信息:
纯右值指的是“纯粹意义上”的临时对象:编译器可以绝对确定地判断其评估是一个刚刚创建且立即过期的临时对象的表达式(除非我们通过引用绑定进行干预以延长其生命周期)。该对象是在表达式求值期间创建的,并且它将根据“母表达式”的规则消亡。
相比之下,过期值是一个表达式,其计算结果是对承诺很快过期的对象的引用。也就是说,它给了你一个承诺,你可以对这个对象做任何你想做的事情,因为无论如何它接下来都会被销毁。但你不知道这个对象何时被创建,或者何时应该被销毁。你只知道你“拦截”了它,因为它即将死去。
在实践中:
struct X;
auto foo() -> X;
Run Code Online (Sandbox Code Playgroud)
X x = foo();
^~~~~
Run Code Online (Sandbox Code Playgroud)
在此示例中,评估foo()将产生prvalue. 只需查看这个表达式,您就知道该对象是作为返回的一部分而创建的foo,并将在完整表达式结束时被销毁。因为您了解所有这些事情,所以您可以延长其使用寿命:
const X& rx = foo();
Run Code Online (Sandbox Code Playgroud)
现在 foo 返回的对象的生命周期延长到了rx
auto bar() -> X&&
Run Code Online (Sandbox Code Playgroud)
X x = bar();
^~~~
Run Code Online (Sandbox Code Playgroud)
在此示例中,评估bar()将产生一个xvalue. bar 向你承诺它给你一个即将过期的对象,但你不知道这个对象是什么时候创建的。它可以在调用之前创建bar(无论是否临时),然后为bar您提供一个rvalue reference。优点是你知道你可以用它做任何你想做的事情,因为它之后不会被使用(例如你可以离开它)。但你不知道这个对象什么时候应该被销毁。因此,您无法延长其生命周期 - 因为您首先不知道其原始生命周期是多少:
const X& rx = bar();
Run Code Online (Sandbox Code Playgroud)
这不会延长寿命。
| 归档时间: |
|
| 查看次数: |
800 次 |
| 最近记录: |