Lifetime extension, prvalues and xvalues - c++

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.

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++
Note that value categories describe expressions not objects. Value categories ( xvalue, prvalue, or whatever ) won't be extended in any way. Only objects can have a lifetime.
From the n4296 standard draft:
§12.2.1
Temporaries of class type are created in various contexts: binding a reference to a prvalue (8.5.3), returning
a prvalue (6.6.3), a conversion that creates a prvalue (4.1, 5.2.9, 5.2.11, 5.4), throwing an exception (15.1),
and in some initializations (8.5).
and
§12.2.4
There are two contexts in which temporaries are destroyed at a different point than the end of the full-
expression. [...]
The second context is when a reference is bound to a temporary. 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
Note: I didn't quote the first context since it has minor revelance regarding the questions. Italic emphasis added by me.
Thus the value category of the function expression makesomething() is a prvalue creating a temporary of class type, according to the first paragraph cited above.
makesomething().a accesses a temporary, complete subobject. Binding this temporary to a reference leads, according to the second context quoated above, to an extended lifetime.
The lifetime of the subobject a is coupled to the lifetime of the previous created temporary making it an expiring value (xvalue). Without extending its lifetime by binding it to a reference it would be destroyed together with the temporary class object. Thus, in this case, after the ;.

Related

Why the different behaviors shown below between an lvalue and an rvalue reference? [duplicate]

With code like
#include <stdio.h>
struct P2d {
double x, y;
P2d(double x, double y) : x(x), y(y) {}
~P2d() { printf("Destructor called\n"); }
};
P2d center() {
return P2d(10, 10);
}
int main(int argc, const char *argv[]) {
const double& x = center().x;
printf("x = %.18g\n", x);
return 0;
}
g++ (version 5.2.0) will destroy the P2d temporary instance before entering the printf in main, but the value will be preserved anyway (i.e. instead of binding x to the actual member of the temporary P2d instance it will create another temporary double to copy the value of the member).
clang++ (IMO correctly) instead extends the lifetime of the temporary P2d instance to the lifetime of the x reference and the destructor will be therefore called after the printf in main.
If instead of using plain double as type for the x and y members you make a class (e.g. Double) then both compilers agree and they extend the lifetime of the temporary P2d object to past the printf.
Is this a bug in g++ or something allowed by the standard?
This is covered by CWG 1651:
The resolution of issues 616 and 1213, making the result of a member
access or subscript expression applied to a prvalue an xvalue, means
that binding a reference to such a subobject of a temporary does not
extend the temporary's lifetime. 12.2 [class.temporary] should be
revised to ensure that it does.
The status quo is that only prvalues are treated as referring to temporaries - thus [class.temporary]/5 ("The second context is when a reference is bound to a temporary.") is not considered applicable. Clang and GCC have not actually implemented issue 616's resolution, though. center().x is treated as a prvalue by both. My best guess:
GCC simply didn't react to any DRs yet, at all. It doesn't extend lifetime when using scalar subobjects, because those are not covered by [dcl.init.ref]/(5.2.1.1)†. So the complete temporary object doesn't need to live on (see aschelper's answer), and it doesn't, because the reference doesn't bind directly. If the subobject is of class or array type, the reference binds directly, and GCC extends the temporary's lifetime. This has been noted in DR 60297.
Clang recognizes member access and implemented the "new" lifetime extension rules already - it even handles casts. Technically speaking, this is not consistent with the way it handles value categories. However, it is more sensible and will be the correct behavior once the aforementioned DR is resolved.
I'd therefore say that GCC is correct by current wording, but current wording is defective and vague, and Clang already implemented the pending resolution to DR 1651, which is N3918. This paper covers the example very clearly:
If E1 is a temporary expression and E2 does not designate a
bit-field, then E1.E2 is a temporary expression.
center() is a temporary expression as per the paper's wording for [expr.call]/11. Thus its modified wording in the aforementioned [class.temporary] /5 applies:
The second context is when a reference does not bind directly (8.5.3
dcl.init.ref) or is initialized with a temporary expression (clause 5). The corresponding temporary
object (if any) persists for the lifetime of the reference except: [...inapplicable exceptions...]
Voilà, we have lifetime extension. Note that "the corresponding temporary object" is not clear enough, one of the reasons for the proposal's deferment; it will assuredly be adopted once it gets revised.
†
is an xvalue (but not a bit-field), class prvalue, array prvalue or function lvalue and “cv1 T1” is reference-compatible with “cv2 T2”, or […]
Indeed, GCC respects this fully and will extend lifetime if the subobject has array type.
I would argue for a bug in g++, because, quoting draft N3242, §12.2/5:
The second context is when a reference is bound to a temporary. 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 except:
So its lifetime must be extended, except when:
A temporary bound to a reference member in a constructor’s ctor-initializer [..]
A temporary bound to a reference parameter in a function call [..]
The lifetime of a temporary bound to the returned value in a function return statement [..]
A temporary bound to a reference in a new-initializer [..]
Our case doesn't fit any of these exceptions, thus it must follow the rule. I'd say g++ is wrong here.
Then, regarding the quote aschepler brought up from the same draft §8.5.3/5 (emphasis mine):
A reference to type "cv1 T1" is initialized by an expression of type "cv2 T2" as follows:
If the reference is an lvalue reference and the initializer expression
a. is an lvalue (but is not a bit-field) and "cv1 T1" is reference-compatible with "cv2 T2", or
b. has a class type ...
then ...
Otherwise, the reference shall be an lvalue reference to a non-volatile const type (i.e., cv1 shall be const), or the reference shall be an rvalue reference.
a. If the initializer expression
i. is an xvalue, class prvalue, array prvalue or function lvalue and "cv1 T1" is reference-compatible with "cv2 T2", or
ii. has a class type ...
then the reference is bound to the value of the initializer expression in the first case....
b. Otherwise, a temporary of type "cv1 T1" is created and initialized from the initializer expression using the rules for a non-reference copy-initialization (8.5). The reference is then bound to the temporary.
Looking at what an xvalue is, this time quoting http://en.cppreference.com/w/cpp/language/value_category ...
An xvalue ("expiring value") expression is [..]
a.m, the member of object expression, where a is an rvalue and m is a non-static data member of non-reference type;
... the expression center().x should be an xvalue, thus case 2a from §8.5.3/5 applies (and not the copy). I'll stay with my suggestion: g++ is wrong.
Just read Columbo's answer.
This is a gcc bug. The relevant rule is in [class.temporary]:
There are two contexts in which temporaries are destroyed at a different point than the end of the full-expression. [...]
The second context is when a reference is bound to a temporary. 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 except:
— A temporary object bound to a reference parameter in a function call (5.2.2) persists until the completion
of the full-expression containing the call.
— The lifetime of a temporary bound to the returned value in a function return statement (6.6.3) is not
extended; the temporary is destroyed at the end of the full-expression in the return statement.
— A temporary bound to a reference in a new-initializer (5.3.4) persists until the completion of the
full-expression containing the new-initializer.
We're binding a reference to a subobject of a temporary, so the temporary should persist for the lifetime of the reference. None of those three exceptions to this rule apply here.

Member rvalue references and object lifetime

It's been a while since I last looked at temporary lifetime rules and I don't remember how member rvalue references affect
lifetime.
For example take the two following pieces of code:
int main()
{
std::get<0>(std::forward_as_tuple(
[](int v){ std::cout << v << std::endl; }
))(6);
return 0;
}
,
int main()
{
auto t = std::forward_as_tuple(
[](int v){ std::cout << v << std::endl; }
);
std::get<0>(t)(6);
return 0;
}
If member rvalue references don't affect lifetime rules, I would expect the first example to be well-behaved while the second example
to be undefined (since the full-expression containing the lambda object
ends at the first semicolon).
How do C++11, C++14 and C++17 treat the given examples? Are there differences between the three?
Lifetime extension applies when you directly bind a temporary to a reference anywhere but within a constructor initializer list. (Note: aggregate initialization isn't a constructor)
std::forward_as_tuple is a function. Any temporary passed to it cannot be lifetime extended beyond the current line.
Temporaries by default last until the end of the current line, basically. (What exactly that spot is isn't actually the end of the current line). In your two cases, it is the end of the current line (the ;) where the temporary ends its lifetime. This is long enough for the first case; in the second case, the temporary is dead and your code exhibits undefined behavior.
At the same time:
struct foo {
int&& x;
};
int main() {
foo f{3};
std::cout << f.x << "\n";
}
is perfectly well defined. No constructor, we bound a temporary to an (rvalue) reference, thus lifetime is extended.
Add this:
struct foo {
int&& x;
foo(int&& y):x(y) {}
};
or
struct foo {
int&& x;
foo(int y):x((int)y) {}
};
and it is now UB.
The first one because we bound the temporary to an rvalue reference when invoking the ctor. The inside of the constructor is irrelevant, as there is no temporary being bound directly there. Then the argument to the function and the temporary both go out of scope in main.
The second because the rule that binding the temporary (int)y0 to int&&x in a constructor initializer list does not extend lifetime the same way as it does elsewhere.
The rules of temporary lifetime extension haven't changed in any version of C++ since 98. We may have new ways to manifest temporaries, but once they exist, their lifetimes are well understood.
It should be noted that your example doesn't really apply to member references of any kind. You're calling a function with a temporary, and the parameter is a forwarding reference. The temporary in question is therefore bound to the function parameter reference, not to a member reference. The lifetime of that temporary will end after the expression that invoked that function, as it would with any temporary passed to a reference parameter.
The fact that this function (forward_as_tuple) will eventually store that reference in a tuple is irrelevant. What you do with a reference cannot alter its lifetime.
Again, that's C++98, and none of the later versions changed that.
Because this is a language-lawyer question. The rules for lifetime extension are in [class.temporary]. The wording from C++11 to C++14 to C++17 didn't change in a way that is relevant to this particular question. The rule is:
There are [two/three†] contexts in which temporaries are destroyed at a different point than the end of the full-expression. The first context is when a default constructor is called to initialize an element of an array [...]†
The [second/third†] context is when a reference is bound to a temporary. 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 except:
— A temporary object bound to a reference parameter in a function call (5.2.2) persists until the completion
of the full-expression containing the call.
This expression:
std::forward_as_tuple([](int v){ std::cout << v << std::endl; })
involves binding a reference (the parameter in forward_as_tuple) to a prvalue (the lambda-expression), which is explicitly mentioned in C++11/14 as a context which creates a temporary:
Temporaries of class type are created in various contexts: binding a reference to a prvalue, [...]
which in C++17 is worded as:
Temporary objects are created
(1.1) — when a prvalue is materialized so that it can be used as a glvalue (4.4),
Either way, we have a temporary, it's bound to a reference in a function call, so the temporary object persists until the completion of the full-epxression containing the call.
So this is okay:
std::get<0>(std::forward_as_tuple(
[](int v){ std::cout << v << std::endl; }
))(6);
But this calls through a dangling reference:
auto t = std::forward_as_tuple(
[](int v){ std::cout << v << std::endl; }
);
std::get<0>(t)(6);
because the lifetime of the temporary function object ended at the end of the statement initializing t.
Note that this has nothing to do with member rvalue references. If we had something like:
struct Wrapper {
X&& x;
};
Wrapper w{X()};
then the lifetime of the temporary X persists through the lifetime of w, and w.x isn't a dangling reference. But that's because there's no function call.
†C++17 introduced a 3rd context which involves copying an array, which is unrelated here.

With a binded const& to a data member, why is the destructor being called early? [duplicate]

With code like
#include <stdio.h>
struct P2d {
double x, y;
P2d(double x, double y) : x(x), y(y) {}
~P2d() { printf("Destructor called\n"); }
};
P2d center() {
return P2d(10, 10);
}
int main(int argc, const char *argv[]) {
const double& x = center().x;
printf("x = %.18g\n", x);
return 0;
}
g++ (version 5.2.0) will destroy the P2d temporary instance before entering the printf in main, but the value will be preserved anyway (i.e. instead of binding x to the actual member of the temporary P2d instance it will create another temporary double to copy the value of the member).
clang++ (IMO correctly) instead extends the lifetime of the temporary P2d instance to the lifetime of the x reference and the destructor will be therefore called after the printf in main.
If instead of using plain double as type for the x and y members you make a class (e.g. Double) then both compilers agree and they extend the lifetime of the temporary P2d object to past the printf.
Is this a bug in g++ or something allowed by the standard?
This is covered by CWG 1651:
The resolution of issues 616 and 1213, making the result of a member
access or subscript expression applied to a prvalue an xvalue, means
that binding a reference to such a subobject of a temporary does not
extend the temporary's lifetime. 12.2 [class.temporary] should be
revised to ensure that it does.
The status quo is that only prvalues are treated as referring to temporaries - thus [class.temporary]/5 ("The second context is when a reference is bound to a temporary.") is not considered applicable. Clang and GCC have not actually implemented issue 616's resolution, though. center().x is treated as a prvalue by both. My best guess:
GCC simply didn't react to any DRs yet, at all. It doesn't extend lifetime when using scalar subobjects, because those are not covered by [dcl.init.ref]/(5.2.1.1)†. So the complete temporary object doesn't need to live on (see aschelper's answer), and it doesn't, because the reference doesn't bind directly. If the subobject is of class or array type, the reference binds directly, and GCC extends the temporary's lifetime. This has been noted in DR 60297.
Clang recognizes member access and implemented the "new" lifetime extension rules already - it even handles casts. Technically speaking, this is not consistent with the way it handles value categories. However, it is more sensible and will be the correct behavior once the aforementioned DR is resolved.
I'd therefore say that GCC is correct by current wording, but current wording is defective and vague, and Clang already implemented the pending resolution to DR 1651, which is N3918. This paper covers the example very clearly:
If E1 is a temporary expression and E2 does not designate a
bit-field, then E1.E2 is a temporary expression.
center() is a temporary expression as per the paper's wording for [expr.call]/11. Thus its modified wording in the aforementioned [class.temporary] /5 applies:
The second context is when a reference does not bind directly (8.5.3
dcl.init.ref) or is initialized with a temporary expression (clause 5). The corresponding temporary
object (if any) persists for the lifetime of the reference except: [...inapplicable exceptions...]
Voilà, we have lifetime extension. Note that "the corresponding temporary object" is not clear enough, one of the reasons for the proposal's deferment; it will assuredly be adopted once it gets revised.
†
is an xvalue (but not a bit-field), class prvalue, array prvalue or function lvalue and “cv1 T1” is reference-compatible with “cv2 T2”, or […]
Indeed, GCC respects this fully and will extend lifetime if the subobject has array type.
I would argue for a bug in g++, because, quoting draft N3242, §12.2/5:
The second context is when a reference is bound to a temporary. 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 except:
So its lifetime must be extended, except when:
A temporary bound to a reference member in a constructor’s ctor-initializer [..]
A temporary bound to a reference parameter in a function call [..]
The lifetime of a temporary bound to the returned value in a function return statement [..]
A temporary bound to a reference in a new-initializer [..]
Our case doesn't fit any of these exceptions, thus it must follow the rule. I'd say g++ is wrong here.
Then, regarding the quote aschepler brought up from the same draft §8.5.3/5 (emphasis mine):
A reference to type "cv1 T1" is initialized by an expression of type "cv2 T2" as follows:
If the reference is an lvalue reference and the initializer expression
a. is an lvalue (but is not a bit-field) and "cv1 T1" is reference-compatible with "cv2 T2", or
b. has a class type ...
then ...
Otherwise, the reference shall be an lvalue reference to a non-volatile const type (i.e., cv1 shall be const), or the reference shall be an rvalue reference.
a. If the initializer expression
i. is an xvalue, class prvalue, array prvalue or function lvalue and "cv1 T1" is reference-compatible with "cv2 T2", or
ii. has a class type ...
then the reference is bound to the value of the initializer expression in the first case....
b. Otherwise, a temporary of type "cv1 T1" is created and initialized from the initializer expression using the rules for a non-reference copy-initialization (8.5). The reference is then bound to the temporary.
Looking at what an xvalue is, this time quoting http://en.cppreference.com/w/cpp/language/value_category ...
An xvalue ("expiring value") expression is [..]
a.m, the member of object expression, where a is an rvalue and m is a non-static data member of non-reference type;
... the expression center().x should be an xvalue, thus case 2a from §8.5.3/5 applies (and not the copy). I'll stay with my suggestion: g++ is wrong.
Just read Columbo's answer.
This is a gcc bug. The relevant rule is in [class.temporary]:
There are two contexts in which temporaries are destroyed at a different point than the end of the full-expression. [...]
The second context is when a reference is bound to a temporary. 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 except:
— A temporary object bound to a reference parameter in a function call (5.2.2) persists until the completion
of the full-expression containing the call.
— The lifetime of a temporary bound to the returned value in a function return statement (6.6.3) is not
extended; the temporary is destroyed at the end of the full-expression in the return statement.
— A temporary bound to a reference in a new-initializer (5.3.4) persists until the completion of the
full-expression containing the new-initializer.
We're binding a reference to a subobject of a temporary, so the temporary should persist for the lifetime of the reference. None of those three exceptions to this rule apply here.

C++: rvalue reference memory

Since c++ provides references to rvalues i.e. rvalue references which are mainly used to perform move semantics and other memory efficient tasks. But in the following case reference is changing the value of an literal but as we know that literals are read only so how could a reference change the value of some read only variable. Does a rvalue reference allocate it's own memory or it simply changes the value of literal?
#include <iostream>
using namespace std;
int main()
{
int a = 5;
int&& b = 3;
int& c = a;
b++;
c++;
cout << " Value for b " << b << " Value for c " << c << endl;
}
Secondly, when a temporary object is assigned with a reference, reference works with the data of that object. But according to the definition of temporary objects they are deleted as when the expression using them ends. How could the reference act as an alias name to that temporary object if that temporary object is out of memory?
Numeric literals can't be bound to any reference, neither an rvalue reference nor an lvalue reference. Conceptually, a numeric literal creates a temporary object initialized from the literal value and this temporary can be bound to an rvalue references or to const lvalue reference (int const& r = 17;). It seems the relevant quote on literals is 5.1.1 [expr.prim.general] paragraph 1:
A literal is a primary expression. Its type depends on its form (2.14). A string literal is an lvalue; all other literals are prvalues.
When binding a reference directly to a temporary, it's life-time gets extended until the reference goes out of scope. The relevant section for the life time issue is 12.2 [class.temporary] paragraph 5:
The second context is when a reference is bound to a temporary. 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 except:
A temporary bound to a reference member in a constructor’s ctor-initializer (12.6.2) persists until the constructor exits.
A temporary bound to a reference parameter in a function call (5.2.2) persists until the completion of the full-expression containing the call.
The lifetime of a temporary bound to the returned value in a function return statement (6.6.3) is not extended; the temporary is destroyed at the end of the full-expression in the return statement.
A temporary bound to a reference in a new-initializer (5.3.4) persists until the completion of the full-expression containing the new-initializer.

Rvalues vs temporaries

Somebody generalized the statement "Temporaries are rvalues". I said "no" and gave him the following example
double k=3;
double& foo()
{
return k;
}
int main()
{
foo()=3; //foo() creates a temporary which is an lvalue
}
Is my interpretation correct?
Temporaries and rvalues are different (but related) concepts. Being temporary is a property of an object. Examples of objects that aren't tempory are local objects, global objects and dynamically created objects.
Being an rvalue is a property of an expression. The opposite of rvalues are lvalues such as names or dereferenced pointers. The statement "Temporaries are rvalues" is meaningless. Here is the relationsip between rvalues and temporary objects:
An rvalue is an expression whose evaluation creates a temporary object which is destroyed at the end of the full-expression that lexically contains the rvalue.
Note that lvalues can also denote temporary objects!
void blah(const std::string& s);
blah(std::string("test"));
Inside the function blah, the lvalue s denotes the temporary object created by evaluating the expression std::string("test").
Your comment "references are lvalues" is also meaningless. A reference is not an expression and thus cannot be an lvalue. What you really mean is:
The expression function() is an lvalue if the function returns a reference.
No. You are returning a reference to an global double, not a temporary.
The same test with a real temporary would be:
double foo() { return 3.0; }
int main() {
foo() = 2.0; // error: lvalue required as left operand of assignment
}
EDIT:
The answer was meant just to identify that the example was wrong, and I did not really want to get into the deeper discussion of whether temporaries are or not rvalues... As others have said, lvalue-ness or rvalue-ness are properties of an expression and not of the object (in the most general sense, not only class instances). Then again, the standard says that:
§3.10/5 The result of calling a function that does not return a reference is an rvalue. User defined operators are functions, and whether such operators expect or yield lvalues is determined by their parameter and return types.
§3.10/6 An expression which holds a temporary object resulting from a cast to a nonreference type is an rvalue (this includes the explicit creation of an object using functional notation (5.2.3)).
Which AFAIK are the circumstances under which temporaries are created. Now, it is also true that you can bind a constant reference to a temporary, in which case you will get a new variable (the reference) that can be used as an lvalue that effectively refers to the temporary object.
The fine line is that expressions that create temporaries are rvalue expressions. You can bind a constant reference to the result of that expression to obtain a variable that can be used as an const-qualified lvalue expression.
Temporaries were so consistently protected from becoming lvalues, that they are now called rvalues. But C++0x will allow temporaries to become lvalues thanks to move semantics. Like in this dumb snippet
void blah(ICanBeTemporary && temp)
{
temp.data = 2; //here temporary becomes lvalue
}
//somewhere
blah(ICanBeTemporary("yes I can"));
Now we have terminology mess. People used to call temporaries rvalues and this is called rvalue reference. Named objects are now considered to be non-rvalue referenced.