Difference in the end of lifetime rules?

  • A+

https://en.cppreference.com/w/cpp/language/lifetime in Notes section has this code, reproduced here:

struct A {   int* p;   ~A() { std::cout << *p; } // if n outlives a, prints 123 }; void f() {   A a;   int n = 123; // if n does not outlive a, this is optimized out (dead store)   a.p = &n; } 

What is it trying to say in this Notes section?

From what I understand, the code is UB (or is it) as it's clear that n does not outlive a.

What does it mean by:

difference in the end of lifetime rules between non-class objects (end of storage duration) and class objects (reverse order of construction) matters

But it does not say matter how.

I am very confused by this entire section.


This is an odd aspect of C++'s lifetime rules. [basic.life]/1 tells us that an object's lifetime ends:

  • if T is a class type with a non-trivial destructor ([class.dtor]), the destructor call starts, or
  • the storage which the object occupies is released, or is reused by an object that is not nested within o ([intro.object]).

Emphasis added. int is not a "class type with a non-trivial destructor", so its lifetime only ends when the storage it occupies is released. By contrast, A is a class type with a non-trivial destructor", so its lifetime ends when the destructor gets called.

The storage for a scope is released when the scope exits, pursuant to [basic.stc.auto]/1:

The storage for [variables with automatic storage duration] lasts until the block in which they are created exits.

But automatic variables are destroyed in accord with [stmt.jump]/2:

On exit from a scope (however accomplished), objects with automatic storage duration that have been constructed in that scope are destroyed in the reverse order of their construction.

Notice that the order of destruction is specified, but the order of automatic storage release is not specified. This means that the implementation could release the storage right after each variable is destroyed, or release it all at once later, or in some arbitrary other order.

Now, the fact that it uses the singular for storage ("the storage for ... lasts") rather than talking about each variable individually may suggest that the intent is for the storage as a whole to be released at once for that scope. But there is no explicit statement of this in the standard. So as long as a variable is destroyed before its storage is released, any ordering of destruction vs. release appears to be legal.

This means it is entirely possible for the code to work, for n to outlive a. But it is unspecified whether it does work.


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: