The C++ standard draft N4296 says
[class.temporary/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 I want to know what happens if two or more references are bound to a temporary. Is it specific in the standard? The following code may be an example:
#include <iostream> //std::cout
#include <string> //std::string
const std::string &f() {
const std::string &s = "hello";
static const std::string &ss = s;
return ss;
}
int main() {
const std::string &rcs = f();
std::cout << rcs; //empty output
//the lifetime of the temporary is the same as that of s
return 0;
}
If we change the bounding order, the case is different.
#include <iostream> //std::cout
#include <string> //std::string
const std::string &f() {
static const std::string &ss = "hello";
const std::string &s = ss;
return ss;
}
int main() {
const std::string &rcs = f();
std::cout << rcs; //output "hello"
//the lifetime of the temporary is the same as that of ss
return 0;
}
The compilation is done on Ideone.com.
I guess [class.temporary/5] only holds when the first reference is bound to the temporary, but I cannot find an evidence in the standard.
The lifetime of a reference begins when its initialization is complete and ends as if it were a scalar object. Note: the lifetime of the referred object may end before the end of the lifetime of the reference, which makes dangling references possible.
Every object and reference has a lifetime, which is a runtime property: for any object or reference, there is a point of execution of a program when its lifetime begins, and there is a moment when it ends.
The lifetime of a temporary object created when evaluating the default arguments of a default or copy constructor used to initialize an element of an array ends before the next element of the array begins initialization.
The lifetime of an object ends when: if it is of a non-class type, the object is destroyed (maybe via a pseudo-destructor call) (since C++20), or if it is of a class type, the destructor call starts, or the storage which the object occupies is released, or is reused by an object that is not nested within it.
This is a defect in that section that I reported as http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1299 .
The proposed resolution is to add a term "temporary expressions". Life-time extension only happens for objects referred to by temporary expressions.
Here's my original report which I privately emailed. I think it makes clear what it's about
In the model of the Standard, there appears to be a distinction about temporary objects, and temporary expressions.
Temporary objects are created by certain operations operations, like functional casts to class types. Temporary objects have a limited specified lifetime.
Temporary expressions are expressions that are so attributed because they are used to track whether or not an expression refers to a temporary object for the purpose of determining whether or not the lifetime of their referent is lengthened when bound by a reference. Temporary expressions are compile time entities.
Several paragraphs refer to "temporaries", but do not explicitly specify whether they refer to temporary objects referred to by arbitrary expressions, or whether they refer only to temporary expressions. The paragraphs about RVO (paragraph 12.8p31) use "temporary" in the sense of temporary objects (they say such things like "temporary class object that has not been bound to a reference"). The paragraphs about lifetime lengthening (sub-clause 12.2) refer to both kinds of temporaries. For example, in the following, "*this" is not regarded as a temporary, even though it refers to a temporary
struct A { A() { } A &f() { return *this; } void g() { } }; // call of g() is valid: lifetime did not end prematurely // at the return statement int main () { A().f().g(); }
As another example, core issue 462 handles about temporary expressions (making a comma operator expression a temporary, if the left operand was one). This appears to be very similar to the notion of "lvalue bitfields". Lvalues that track along that they refer to bitfields at translation time, so that reads from them can act accordingly and that certain reference binding scenarios can emit diagnostics.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With