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:
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).
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 ofstd::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.