对于这个问题的广泛性,我感到抱歉,只是所有这些细节都紧密地联系在一起。
我一直在尝试理解两个值类别之间的区别-xvalues和prvalues,但我仍然感到困惑。
无论如何,我试图为“身份”这一概念为自己开发的思维模型是,应保证具有该身份的表达式驻留在实际程序的数据存储器中。
出于这个原因,字符串字面量是左值,保证它们在整个程序运行时都驻留在内存中,而数字字面量是prvalues,例如假设将其存储在纯组件中。
prvalue文字中的std::move
似乎也是如此,即,当调用fun(1)
时,在被调用方框架中我们只会得到参数lvalue,但是当调用fun(std::move(1))
时,必须将glvalue的xvalue'种类'保留在调用方框架中。
但是,这种心理模型至少不适用于临时对象,据我所知,临时对象应始终在实际内存中创建(例如,如果使用prvalue参数像fun(MyClass())
这样调用rvalue-ref-take-func函数)。因此,我认为这种心理模型是错误的。
那么,思考xvalues的'identity'属性的正确方法是什么?我已经读过,我可以用身份来比较地址,但是如果我可以比较2个MyClass().member
s(根据cppreference的xvalue)的地址,可以说是通过rvalue refs将它们传递给某些比较函数,那么我不明白为什么2 MyClass()
(prvalue)不能做同样的事情吗?
与此相关的另一个来源是这里的答案:
What are move semantics?
但这似乎与“可以比较地址”无关,并且a)我不认为这与右值的“传统意义”有什么不同; b)我不明白为什么这样的原因需要在语言中添加一个新的值类别(好吧,这允许在面向对象的意义上为对象提供动态类型,但是xvalues不仅指对象)。
最佳答案
我个人还有另一个心理模型,它不能直接处理身份和记忆等问题。prvalue
来自“pure rvalue”,而xvalue
来自“expiring value”,这是我在心理模型中使用的以下信息:
纯右值是指“纯粹”意义上的临时对象:对于该表达式,编译器可以绝对确定地告诉其评估是一个刚刚创建且即将到期的临时对象。 (除非我们通过引用绑定(bind)进行干预以延长其寿命)。该对象是在表达式的求值期间创建的,并且将根据“母表达式”的规则而死亡。
相比之下,到期值是一个表达式,其结果是对对一个对象的引用,该对象 promise 将很快过期。那就是给您一个保证,您可以对这个对象做任何您想做的事情,因为它无论如何接下来都会被销毁。但是您不知道何时创建该对象,或何时将该对象销毁。您只知道您“拦截”了它,因为它即将死亡。
在实践中:
struct X;
auto foo() -> X;
X x = foo();
^~~~~
在此示例中,评估
foo()
将产生prvalue
。仅通过查看此表达式,您就知道此对象是作为foo
返回的一部分创建的,并且在此完整表达式的末尾将被销毁。因为您了解所有这些事情,所以可以为它添加一生:const X& rx = foo();
现在foo返回的对象的生存期延长到
rx
的生存期auto bar() -> X&&
X x = bar();
^~~~
在此示例中,评估
bar()
将产生xvalue
。 bar
向您保证会给您一个即将到期的对象,但是您不知道何时创建该对象。可以在调用bar
之前(无论是否临时)创建它,然后bar
为您提供一个rvalue reference
。好处是您知道您可以使用它做任何您想做的事情,因为它不会被使用后缀(例如,您可以从它移走)。但是您不知道何时应该销毁该对象。因此,您无法延长其使用寿命-因为您一开始不知道其最初的使用寿命:const X& rx = bar();
这不会延长使用寿命。
关于c++ - xvalues与prvalues:身份属性添加了什么,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/45317763/