对于非pod对象,xvalue和右值在允许使用或行为方面的差异示例是什么?

What is an example of a difference in allowed usage or behavior between an xvalue and a prvalue FOR NON-POD objects?

本文关键字:方面 是什么 许使用 对象 pod 于非 xvalue      更新时间:2023-10-16

什么是右值、左值、左值、右值和右值?对右值/左值的分类进行了很好的概述,最近对这个问题的一个回答(https://stackoverflow.com/a/9552880/368896)强调了左值"类似于"老式的右值,而新的xvalue允许"类似于左值"的行为。

但是,考虑以下代码:

class X {};
X foo() { return X(); }
int main()
{
    foo() = X(); // foo() is a prvalue that successfully appears on the lhs
}

在本例中,表达式foo()是出现在左侧的右值,并接受赋值。

这让我思考-"x值"不同于"右值"的逻辑,因为x值(它们是glvalues)可以出现在左侧,似乎被这个例子打破了。这里我们有一个右值——它不是左值——在lhs上成功出现并接受赋值。

(注意:在POD的情况下,上面的示例无法编译,因此对于POD, xvalue和前值之间的区别似乎是有意义的。因此,这个问题是专门针对非pod类型的。)

那么,在允许的用法或行为上,xvalue和prvalue之间的真正区别是什么,以至于需要将这种区别写入标准?举一个不同的例子就是一个很好的替代答案。

附录

Pubby的评论是正确的。编译器会扩展右值的生存期,但xvalue的生存期不会。

那么,下面是问题的答案:

考虑以下代码:

// ***
// Answer to question, from Pubby's comment
// ***
class X
{
public:
    X() : x(5) {}
    int x;
};
X foo() { return X(); }
X&& goo() { return std::move(X()); } // terrible coding, but makes the point
int main()
{
    foo() = X();
    X&& x1 = foo(); // prvalue - lifetime extended!  Object resides directly on stack as return value
    X&& x2 = goo(); // xvalue - lifetime not extended.  Object (possibly polymorphic) resides somewhere else.
    x1.x = 6;
    x2.x = 7; // Danger!
    std::cout << x1.x << std::endl; // Just fine
    std::cout << x2.x << std::endl; // prints garbage in VS 2012
}

这说明了右值和xvalue在行为上的不同。这里我们有相同的客户端代码,除了绑定的不同(prvalue和xvalue)。

如示例代码所示,右值的生存期会自动延长,但xvalue的生存期不会。

还揭示了其他明显的区别:对于右值,对象本身作为函数的返回值出现在堆栈上;相应地,因为右值的静态类型保证是它的动态类型(见下面的答案),所以延长它的生命周期是有意义的,并且可以由编译器完成。

另一方面,对于xvalue,对象位于某个未知的任意位置,因此编译器无法轻松地延长其生命周期,特别是考虑到该类型可能是多态的。

谢谢你的回答

对于多态非pod类型xvalue表达式,表达式的动态类型通常在编译时是未知的(因此对它们的类型id表达式进行计算,并且虚拟函数调用通常不能去虚拟化)。

对于左值则不适用。动态类型等于静态类型

另一个区别是decltype(e)是xvalues的右值引用类型,而右值的非引用类型。

另一个区别是左值到右值的转换不是对右值进行的(它们已经是结果将产生的)。这可以通过一些相当奇怪的代码

观察到。
struct A { 
    int makeItANonPod; 
    A() = default;
  private:
    int andNonStdLayout;
    A(A const&) = default;
};
void f(...);
int main() {
  f(A()); // OK
  f((A&&)A()); // illformed
}

x值和右值之间的真正区别是什么?xvalue是一种可以被cv限定的右值,引用对象,其动态类型等于或不等于静态类型。

const int&& foo();
int&& _v=foo();

如果没有xvalue,上述函数foo的返回值只能是右值。但是内置类型没有const右值!因此,上述非const变量_v总是可以绑定foo()的返回值,即使我们希望foo()返回一个const右值。