What determines when the lifetime of time series expands to constant references or rvalue references?

Given:

struct hurg { ... };

hurg get_hurg() { return hurg(); }
hurg&& get_mhurg() { return hurg(); }

      

My understanding and experimentation shows that the following behavior is undefined (EDIT: thanks to the answers, it turns out I was wrong, and the examples get_mhurg()

are undefined behavior):

{
    const hurg& a = get_hurg(); 
    hurg&& b = get_hurg();
    const hurg& c = get_mhurg(); 
    hurg&& d = get_mhurg();
    // do stuff with a, b, c, d
}
// a, b, c, d are now destructed

      

That is, the lifetime of the temporary object hurg

returned by get_hurg()

and get_mhurg()

expands to the end of the region.

However, in case (function from here ):

template <typename T>
auto id(T&& x) -> decltype(auto) { return decltype(x)(x); }    

      

Using it like:

{
    const hurg& x = id(hurg()); 
    // the hurg() 'x' refers to is already destructed

    hurg&& y = id(hurg());
    // the hurg() 'y' refers to is already destructed

    // undefined behavior: use 'x' and 'y'
}

      

In this case, the lifetime hurg

does not increase.

What determines when the lifespan of temporary objects generally extends? And in particular, when is it safe to bind the result of a function to an lvalue ref or rvalue ref constant?

And more specifically, what exactly happens in the case id

?

+3


source to share


2 answers


From [class.temporary]:

There are two contexts in which temporary objects are destroyed at a different point than the end of the fullexpression. The first context is when the default constructor is called to initialize an array element [...]

The second context is when the binding is tied to a temporary. A temporary referenced by a linked, or a temporary that is the complete object of the sub-object to which the link is anchored, is preserved for the lifetime of the link, except:
(5.1). The temporary object bound to the reference parameter in the function call (5.2.2) is maintained until the completion of the complete expression containing the call.
(5.2) - The lifetime of a temporary binding to a return value in a function return statement (6.6.3) is not extended ; the temporary is destroyed at the end of the complete expression in the return statement.
(5.3). The temporary binding to the reference in the new initializer (5.3.4) is retained until completion of the complete expression containing the new initializer.



So two things. First, the get_mhurg

behavior is undefined. The lifetime of the temporary you return is not . Secondly, the temporary transition to id

lasts until the end of the full expression containing the function call, but no further. As is the case with get_mhurg

, the temporary extension does not apply. So this will also be undefined behavior.

+6


source


My understanding and experiments show that the following undefined behavior:

Okay, your understanding and experimentation is wrong. Advice for the wise - don't experiment with undefined behavior. For example, your experiment might accidentally happen to show that this is well-defined behavior, which is one of the possible outcomes of undefined behavior.

Using the return value get_mhurg()

is undefined behavior. You gain access to the temporary hurg()

outside of the area in which it was created.



The situation id

just goes to show that life extension is fucking stupid.

In particular, the lifespan extension applies directly to values. It never applies to any links. You must initialize the link with a value. id

does not return a value, so the lifespan extension is not applied.

+4


source







All Articles