Xvalues与prvalues:身份属性添加了什么
对于问题的广泛性,我感到抱歉,只是所有这些细节都紧密相关。
我一直试图理解具体的两个值类别 - xvalues和prvalues之间的区别,但我仍然感到困惑。
具有身份(使得x值与prvalue不同)的属性在SO上的以下问题中讨论:
说xvalues具有身份并且可移动是否正确?
首先,被接受的答案引用了关于xvalue定义的§5/ 7; cppreference(http://en.cppreference.com/w/cpp/language/value_category)提供了一个更广泛的xvalue定义 - 即使我们只考虑5/7中的后两种情况,根据cppreference(以及编译器我也知道)第一个表达式可以是通用右值,不一定是xvalue。 那么哪个来源在这里更加正确?
无论如何,我试图为“身份”这个概念开发自己的心智模式是,拥有它的表达应该保证存在于实际程序的数据存储器中。
由于这个原因,字符串文字是左值,它们保证在整个程序运行时驻留在内存中,而数字文字是预估值,并且可以假设存储在直接的asm中。
这同样适用于从prvalue文字的std::move
,也就是说,当调用fun(1)
我们只会在被调用者框架中获得参数左值,但当调用fun(std::move(1))
,xvalue'kind '必须保留在来电框中。
然而,这种思维模式至少不能用于临时对象,据我所知,它应该始终在实际内存中创建(例如,如果一个右值ref-taking func被称为fun(MyClass())
并带有一个前值论据)。 所以我猜这个心智模式是错误的。
那么考虑xvalues的“身份”属性的正确方法是什么? 我读过身份证明,我可以比较地址,但如果我可以比较2 MyClass().member
s(xvalue根据cppreference)的地址,让我们说通过rvalue refs将它们传递给某个比较函数,不明白为什么我不能用2 MyClass()
(prvalue)做同样的事情?
与此相关的另一个来源是这里的答案:什么是移动语义?
请注意,即使std :: move(a)是一个右值,它的评估也不会创建一个临时对象。 这个难题迫使委员会引入第三个价值类别。 可以绑定到右值引用的东西,即使它不是传统意义上的右值,也称为xvalue(eXpiring值)。
但是这似乎与'可以比较地址'和'a)我没有看到这与传统意义上的右值有什么不同。 b)我不明白为什么这样的理由需要在语言中使用新的值类别(好吧,这允许为OO意义上的对象提供动态类型,但是x值不仅仅指向对象)。
我个人有另一种心智模式,它不直接涉及身份和记忆以及什么。
prvalue
来自“纯粹的右值”,而xvalue
来自“到期值”,这是我在我的心智模型中使用的信息:
纯粹的右值指的是在“纯粹意义上”是一个临时对象:一个表达式,编译器可以绝对肯定地告诉它,它的评估是一个临时对象,它是刚刚创建并且即将过期的对象(除非我们通过参考绑定来介入以延长它的寿命)。 该对象是在评估表达式时创建的,它将根据“母表达式”的规则而死亡。
相比之下, 到期值是一个表达式,该表达式评估对即将到期的对象的引用。 这是它给了你一个承诺,你可以做任何你想要的东西,因为它将被破坏。 但是你不知道这个对象是什么时候创建的,或者它应该被销毁的。 你只知道你“截获”了它,因为它即将死亡。
在实践中:
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();
这不会延长寿命。
当调用func(T&& t)
,调用者说“有在这里”,还有“我不在乎你在做什么”。 C ++没有指定“here”的性质。
在引用参数作为地址实现的平台上,这意味着必须存在某个对象。 在该平台身份==地址。 然而,这不是语言的要求,而是平台调用约定。
一个平台可以简单地通过安排在呼叫者和被呼叫者中以特定方式登记对象来实现引用。 这里的身份可以是“注册edi”。
链接地址: http://www.djcxy.com/p/72999.html