且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

生命周期扩展,prvalues和xvalues

更新时间:2023-01-25 17:25:45

生命周期扩展不关心值类别。如[class.temporary] / p6所述:


引用所绑定的临时对象或作为其完整对象的临时对象

添加了重点。 p>

这里没有说出所引用表达式的值类别。



确定是否扩展了临时变量的原因是







但这并不能解释为什么在将引用分配到的临时目录周围添加 std :: move()不会延长生存期


std :: move 不是C ++中由编译器定义的神奇构造。这是一个函数调用,因此它的行为与任何其他C ++函数调用都没有区别。



因此,如果您拥有 std :: move(Type()),这是什么意思?这意味着您将创建一个临时文件,并将其绑定到 std :: move 参数,然后调用该函数,它将返回一些内容。



如[class.temporary] / p6中所述,将一个临时对象绑定到一个函数参数,意味着该临时对象的生存期固定为完整对象的生存期。创建它的表达式(如果不是该规则的话,则临时函数必须在函数调用结束时销毁,因为那是引用生命周期的结束)。



函数做什么,说什么或隐含什么都没有关系。编译器是否可以内联事物并确定返回值是对来自临时变量的引用,这并不重要。该临时变量的生命周期固定在表达式上,而不是扩展。


Following the well accepted answer to this question Do rvalue references allow dangling references? It would seem that xvalues do not have their lifetime extended when assigned to a rvalue reference lvalue like in the question. However when I do this

#include <iostream>

using namespace std;

class Something {
public:
    Something() {
        cout << "Something()" << endl;
    }
    Something(const Something&) {
        cout << "Something(const Something&)" << endl;
    }
    Something(Something&&) {
        cout << "Something(Something&&)" << endl;
    }
    ~Something() {
        cout << "~Something()" << endl;
    }

    int a;
};

Something make_something() {
    return Something{};
}

int main() {
    auto&& something = make_something().a;

    return 0;
}

The lifetime of the object returned by a call to make_something is extended, even though make_something().a is an xvalue as per http://en.cppreference.com/w/cpp/language/value_category (the third bullet in the xvalues explanation lists the member access I have above as an xvalue,)

a.m, the member of object expression, where a is an rvalue and m is a non-static data member of non-reference type;

If value categories do not determine when the lifetime of an rvalue will be extended then what does? I am having a hard time understanding when the lifetime of an rvalue is extended in C++

Lifetime extension doesn't care about value categories. As stated by [class.temporary]/p6:

The temporary to which the reference is bound or the temporary that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference

Emphasis added.

This says nothing here about the value category of the expression being referenced.

What determines whether a temporary is extended is exactly the above (and a few more rules).


But that does not explain why adding an std::move() around the temporary to which the reference is being assigned does not extend the lifetime

std::move is not a magical, compiler-defined construct in C++. It is a function call, and therefore it behaves no differently from any other C++ function call.

So, if you have std::move(Type()), what does that mean? It means that you will create a temporary, bind it to the parameter of std::move, then call that function, which will return something.

Binding a temporary to a function parameter, as stated in [class.temporary]/p6, means that the lifetime of the temporary is fixed to be the lifetime of the full expression that created it (if not for that rule, then the temporary would have to be destroyed at the end of the function call, since that's the end of the reference's lifetime).

It doesn't matter what the function does, says, or implies. It doesn't matter if the compiler could perhaps inline things and determine that the return value is a reference to an argument that came from a temporary. The lifetime of that temporary is fixed to the expression, not extended.