对于非POD对象,xvalue和prvalue之间的允许使用或行为有什么不同? [英] What is an example of a difference in allowed usage or behavior between an xvalue and a prvalue FOR NON-POD objects?

查看:126
本文介绍了对于非POD对象,xvalue和prvalue之间的允许使用或行为有什么不同?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

什么是右值,左值,x值,glvalues和prvalues? 全面介绍了右值/左值的分类,以及该问题的最近解答之一( http:// stackoverflow.com/a/9552880/368896 )强调的是,prvalues是like旧的右值,而新的xvalues允许像左值的行为。



但是,请考虑以下代码:

  class X {}; 
X foo(){return X(); }

int main()
{
foo()= X(); // foo()是成功出现在lhs上的prval值
}

例如,表达式 foo()是显示在左侧的prvalue,并接受赋值。



这让我想到 - xvalues不同于prvalues的逻辑,因为xvalues(他们是glvalues)可以出现在左手边,似乎被这个例子打破了。这里我们有一个prvalue - 它不是glvalue - 成功地出现在lhs并接受赋值。



(注意:在POD的情况下,上面的例子不会编译,所以对于POD,xvalues和prvalues之间的区别似乎是有意义的。因此,这个问题具体是关于非POD类型。)



,是xvalue和prvalue之间的允许使用或行为的真正差异,是否需要将这种区别写入标准?



> Pubby的评论是正确的。 prvalue的生命周期由编译器扩展,但xvalue的生命周期不是。



因此,这里是一个问题的答案:



请考虑以下代码:

  // *** 
//回答问题,来自Pubby的评论
// ***

class X
{
public:
X():x(5){ }
int x;
};

X foo(){return X(); }
X&& goo(){return std :: move(X()); } //可怕的编码,但是让点

int main()
{
foo()= X();
X&& x1 = foo(); // prvalue - lifetime extended!对象作为返回值直接驻留在栈上
X&& x2 = goo(); // xvalue - lifetime not extended。对象(可能是多态)驻留在其他地方。
x1.x = 6;
x2.x = 7; // 危险!

std :: cout<< x1.x<< std :: endl; // Just fine
std :: cout<< x2.x < std :: endl; //在VS 2012中打印垃圾
}

这表明prvalue ,和xvalue。这里我们有相同的客户端代码,除了绑定的差异(prvalue vs. xvalue)。



如示例代码所示,prvalue的生命周期自动扩展, xvalue的生命周期不是。



还有其他明显的差异显示:对于prvalue,对象本身出现在堆栈上作为返回值的功能;相应地,因为prvalue的静态类型被保证是它的动态类型(见下面的答案),所以扩展它的生命周期是有意义的,可以由编译器来完成。



另一方面,对于xvalue,对象在某些未知的,任意位置,因此编译器不能轻易地延长其生命周期,特别是假定类型可以是多态的。



谢谢答案。

解决方案

对于多态非pod类型xvalue表达式,表达式的动态类型通常在编译时是未知的时间(因此对它们的typeid表达式进行求值,而虚拟函数调用通常不会被虚拟化)。



对于prvalues,不适用。



另一个区别是 decltype(e)是一个右值引用类型



另一个区别是,对于prvalues没有进行右值转换的左值(它们已经是结果会产生的结果) 。这可以通过一些很奇怪的代码来观察。

  struct A {
int makeItANonPod;
A()= default;

private:
int andNonStdLayout;
A(A const&)= default;
};

void f(...);

int main(){
f(A()); // OK
f((A&&)A()); // illformed
}


What are rvalues, lvalues, xvalues, glvalues, and prvalues? gives a good overview of the taxonomy of rvalues/lvalues, and one of the recent answers to that question (http://stackoverflow.com/a/9552880/368896) stresses the point that prvalues are "like" the old-style rvalues, whereas the new xvalues allow for "lvalue-like" behavior.

However, consider the following code:

class X {};
X foo() { return X(); }

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

In this example, the expression foo() is a prvalue that appears on the left-hand side, and accepts assignment.

That got me thinking - the logic that "xvalues" differ from "prvalues" because xvalues (glvalues that they are) can appear on the left-hand-side, seems to be broken by this example. Here we have a prvalue - which is not a glvalue - appearing successfully on the lhs and accepting assignment.

(Note: in the case of POD, the above example would not compile, so for POD, the distinction between xvalues and prvalues seems to make sense. Therefore, this question is specifically in regards to non-POD types.)

What, then, is the true difference in either allowed usage, or behavior, between an xvalue and a prvalue, that necessitates this distinction being written into the standard? A single example of a difference would be a fine alternative answer.

ADDENDUM

Pubby's comment was correct. The lifetime of a prvalue is extended by the compiler, but the lifetime of an xvalue is not.

So, here is an answer to the question:

Consider the following code:

// ***
// 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
}

This demonstrates a difference in behavior between a prvalue, and an xvalue. Here we have identical client code except for the difference in binding (prvalue vs. xvalue).

As the sample code demonstrates, the lifetime of the prvalue is automatically extended, but the lifetime of the xvalue is not.

There are other obvious differences revealed, as well: For the prvalue, the object itself appears on the stack as the return value of the function; correspondingly, because a prvalue's static type is guaranteed to be its dynamic type (see answer below), extending its lifetime is meaningful and can be done by the compiler.

On the other hand, for the xvalue, the object is at some unknown, arbitrary location, so the compiler couldn't easily extend its lifetime, especially given that the type could be polymorphic.

Thanks for the answer.

解决方案

For polymorphic nonpod type xvalue expressions, the dynamic type of the expression is generally unknown at compile time (so a typeid expression on them is evaluated, and virtual function calls cannot in general be devirtualized).

For prvalues, that does not apply. The dynamic type equals the static type.

Another difference is that decltype(e) is an rvalue reference type for xvalues and a non-reference type for prvalues.

Yet another difference is that an lvalue to rvalue conversion is not done for prvalues (they are already what the result would yield). This can be observed by some rather weird code

struct A { 
    int makeItANonPod; 
    A() = default;

  private:
    int andNonStdLayout;
    A(A const&) = default;
};

void f(...);

int main() {
  f(A()); // OK
  f((A&&)A()); // illformed
}

这篇关于对于非POD对象,xvalue和prvalue之间的允许使用或行为有什么不同?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆