The life time of a temporary, to which several references are attached in C ++

Standard Draft C ++ N4296 says

[class.temporary / 5] The second context is when the link is tied to a temporary one. Temporary, to which the link is attached, or temporary, which is the full object of the subobject to which the link is attached, is saved for the link lifetime, except ...

So, I want to know what happens if two or more links are tied to a temporary one. Is it a specific standard ? The following example could 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 restrictive 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; } 

Compilation is performed on Ideone.com.

I think [class.temporary / 5] is only executed when the first link is tied to a temporary one, but I cannot find evidence in the standard.

+5
source share
3 answers

This is a defect in this section, which I reported as http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1299 .

The proposed resolution is to add the term “temporary expressions”. The extension of the service life occurs only for objects referenced by temporary expressions.

Here is my original report that I sent by email. I think it clearly shows what it is about

In the Standard model, there appears to be a difference in respect of temporary objects and temporary expressions.

Temporary objects are created using certain operations, such as functional discards of class types. Temporary objects are limited to the specified lifetime.

Temporary expressions are expressions that are so explained because they are used to track whether an expression refers to a temporary object in order to determine whether their referent’s lifetime is lengthened when linking. Temporary expressions are compile-time objects.

Several paragraphs relate to “temporary,” but it does not explicitly indicate whether they refer to temporary objects referenced by arbitrary expressions or whether they refer only to temporary expressions. The paragraphs relating to RVO (clause 12.8p31) use “temporary” in the sense of temporary objects (they say things like “an object of a temporary class that was not attached to a link”). Paragraphs on increasing life expectancy (subparagraph 12.2) apply to both types of temporary. For example, in the following, "* this" is not considered temporary, although it refers to 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, the main problem 462 concerns temporary expressions (making the statement of a comma operator temporary if the left operand was one). This seems to be very similar to the concept of "lvalue bitfields". Lvalues ​​that track that they refer to bit fields at the translation time so that reads from them can act appropriately and that some link binding scripts can emit diagnostics.

+5
source

What you need to know is that the reference return type is not considered temporary for the purposes of this section and will never lead to an extended service life.

(note on pedantry: the standard requires that the link be bound to the value of x, and not just to the temporary one. The second link is linked via an lvalue, not an xvalue.)

Your first example returns a date link - the cout line is undefined. It can print Hello! and it won’t prove anything.

Here is a simpler example:

 template<class T> const T& ident(const T& in) { return in; } int main(void) { const X& ref1 = X(1); // lifetime extension occurs const X& ref2 = ident(X(2)); // no lifetime extension std::cout << "Here.\n"; } 

The order of construction and destruction:

 X(1) X(2) ~X() for X(2) object "Here." is printed ~X() for X(1) object 
+2
source

The first feature presented in the question is

 const std::string &f() { const std::string &s = "hello"; static const std::string &ss = s; return ss; } 

gives Undefined Behavior if a return link is used. The specified object ceases to exist when the first function call is returned. And subsequent ss calls are a dangling link.

life extension standard paragraph context

C ++ 11 §12.2 / 4

" There are two contexts in which temporary objects are destroyed at a different point than the end of the full expression

Ie, all this concerns temporal times that would otherwise be destroyed at the end of the full expression they created.

One of two contexts: with four exceptions noted

C + 11 §12.2 / 5

" & hellip; when the link is bound to [such] temporary

In the above code, the temporary std::string created by the full expression "hello" is bound to the s link, and the lifetime is extended to the region s , which is the body of the function.

Subsequent declaration and initialization of the static link ss does not include the full expression that creates the temporary. Its s initialization expression is not temporary: it is a reference to a local one. Therefore, it is out of context covered by the paragraph of the extension of life.

But how do we know what this means? Well, making sure that the dynamic dynamics refer to what was originally temporary is not computable for the general case, and the C ++ language standard does not include such distant concepts. So simple, really.


IMHO a more interesting case, approx. formal rules

 #include <string> #include <iostream> using namespace std; template< class Type > auto temp_ref( Type&& o ) -> T& { return o; } auto main() -> int { auto const& s = temp_ref( string( "uh" ) + " oh!" ); cout << s << endl; } 

I argue that there is no extension of lifespan here, and that the output statement using the s reference uses a sagging link with the result of UB.

And I think that this conclusion, unlike the choice of OP, for example, cannot be affirmed solely on the basis of the standard formulation, because (it seems to me) the standard formulation is a little inferior. That he cannot make an exception for reference types. But maybe I'm wrong, and if I find out that I will update this answer to reflect this new understanding.

+1
source

Source: https://habr.com/ru/post/1236505/


All Articles