c++ xvalue和prvalue之间的一些区别

ngynwnxp  于 2023-02-10  发布在  其他
关注(0)|答案(2)|浏览(117)

最近我一直在仔细研究C++的分类,左值和右值的区别看起来很清楚,但是当谈到右值和右值的时候我就搞混了。
举个例子:

#include <iostream>
using std::cout;
using std::endl;
using std::move;
class Type {
public:
    int value;
    Type(const int &value=0) :value(value) {}
    Type(const Type &type) :value(type.value){}
    Type(Type &&type) noexcept :value(type.value) {}
    Type &operator= (const Type &type) {
        value = type.value;
        return *this;
    }
    Type &operator=(Type &&type) noexcept{
        value = type.value;
        return *this;
    }
};
Type foo1(const Type &value) {
    return Type(value);
}
Type &&foo2(const Type &value) {
    return Type(value);
}
int main() {
    Type bar1(123);
    cout << foo1(bar1).value << endl;
    cout << foo2(bar1).value << endl;
    Type bar2;
    bar2 = foo1(bar1);
    cout << bar2.value << endl;
    bar2 = foo2(bar1);
    cout << bar2.value << endl;
    return 0;
}

运行该示例,控制台将:

**123人

123
123
-858993460**有人能解释一下为什么它在最后一个输出中给出了一个意外的值吗?
这个例子展示了xvalue的什么特性?

2hh7jdfx

2hh7jdfx1#

foo2正在返回绑定到临时的引用,该临时被立即销毁;它总是返回一个悬挂引用。
不扩展return语句中函数返回值的临时绑定:它在返回表达式的末尾立即被销毁。2这样的函数总是返回一个悬空引用。
对返回的引用(如foo2(bar1).valuebar2 = foo2(bar1);)解引用导致UB;一切皆有可能。
另一方面,foo1没有这个问题,返回值是从临时对象中移出的。

fykwrbwg

fykwrbwg2#

这里有一个非常简单的解释,考虑一下C ++0x之前的教科书例子:

T& f()
{
    T t;
    return t;
}

// ...

T& val = f();
cout << val; // <--- SIGSEGV here

这个代码片段崩溃了,你并不感到惊讶,对吧?你返回了一个引用(实际上,它只不过是一个美化的指针)到一个本地对象,而这个对象在函数返回之前就被销毁了,因此val注定要成为一个悬空引用。
现在考虑一下:

T&& f()
{
    T t;
    return static_cast<T&&>(t);
}

// ...

T&& val = f();
cout << val; // <--- SIGSEGV here

就对象的生命周期而言,这和以前完全一样,右值引用并不是某种神奇的移动对象的全新工具,它是相同的老引用(读作:美化指针)。没有任何变化-你仍然返回了一个被销毁对象的地址。
我假设每个人都同意std::move只不过是一个美化了的static_cast<T&&>,所以如果使用它,结果是一样的:

T&& f()
{
    T t;
    return std::move(t);
}

// ...

T&& val = f();
cout << val; // <--- SIGSEGV here

本例与上例有99.9%相同。
(The 0.1%的差异是,例如,在前两个例子中,GCC知道代码出错了,并且实际上返回了一个空引用,该空引用保证在第一次使用时崩溃;而在最后一个例子中,由于std::move是一个函数,所以它不能确定,所以它顺从地返回坏地址)。

相关问题