[basic.life] (original) (raw)

6 Basics [basic]

6.7 Memory and objects [basic.memobj]

6.7.3 Lifetime [basic.life]

The lifetime of an object or reference is a runtime property of the object or reference.

A variable is said to have vacuous initializationif it is default-initialized, no other initialization is performed, and, if it is of class type or a (possibly multidimensional) array thereof, a trivial constructor of that class type is selected for the default-initialization.

The lifetime of an object o of type T ends when:

When evaluating a new-expression, storage is considered reused after it is returned from the allocation function, but before the evaluation of the new-initializer ([expr.new]).

[Example 1: struct S { int m;};void f() { S x{1};new(&x) S(x.m); } — _end example_]

The lifetime of a reference begins when its initialization is complete.

The lifetime of a reference ends as if it were a scalar object requiring storage.

[Note 1:

[class.base.init]describes the lifetime of base and member subobjects.

— _end note_]

The properties ascribed to objects and references throughout this document apply for a given object or reference only during its lifetime.

[Note 2:

In particular, before the lifetime of an object starts and after its lifetime ends there are significant restrictions on the use of the object, as described below, in [class.base.init], and in [class.cdtor].

Also, the behavior of an object under construction and destruction can differ from the behavior of an object whose lifetime has started and not ended.

[class.base.init]and [class.cdtor] describe the behavior of an object during its periods of construction and destruction.

— _end note_]

A program may end the lifetime of an object of class type without invoking the destructor, by reusing or releasing the storage as described above.

In this case, the destructor is not implicitly invoked.

[Note 4:

The correct behavior of a program often depends on the destructor being invoked for each object of class type.

— _end note_]

Before the lifetime of an object has started but after the storage which the object will occupy has been allocated22or, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, any pointer that represents the address of the storage location where the object will be or was located may be used but only in limited ways.

For an object under construction or destruction, see [class.cdtor].

Otherwise, such a pointer refers to allocated storage ([basic.stc.dynamic.allocation]), and using the pointer as if the pointer were of type void* is well-defined.

Indirection through such a pointer is permitted but the resulting lvalue may only be used in limited ways, as described below.

The program has undefined behavior if

[Example 2: #include <cstdlib> struct B { virtual void f();void mutate();virtual ~B();};struct D1 : B { void f(); };struct D2 : B { void f(); };void B::mutate() { new (this) D2; f(); ... = this; } void g() { void* p = std::malloc(sizeof(D1) + sizeof(D2)); B* pb = new (p) D1; pb->mutate();*pb; void* q = pb; pb->f(); } — _end example_]

Similarly, before the lifetime of an object has started but after the storage which the object will occupy has been allocated or, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, any glvalue that refers to the original object may be used but only in limited ways.

For an object under construction or destruction, see [class.cdtor].

Otherwise, such a glvalue refers to allocated storage ([basic.stc.dynamic.allocation]), and using the properties of the glvalue that do not depend on its value is well-defined.

The program has undefined behavior if

An object is transparently replaceable by an object if

After the lifetime of an object has ended and before the storage which the object occupied is reused or released, if a new object is created at the storage location which the original object occupied and the original object was transparently replaceable by the new object, a pointer that pointed to the original object, a reference that referred to the original object, or the name of the original object will automatically refer to the new object and, once the lifetime of the new object has started, can be used to manipulate the new object.

[Example 3: struct C { int i;void f();const C& operator=( const C& );};const C& C::operator=( const C& other) { if ( this != &other ) { this->~C(); new (this) C(other); f(); } return *this;}C c1; C c2; c1 = c2; c1.f(); — _end example_]

[Note 5:

If these conditions are not met, a pointer to the new object can be obtained from a pointer that represents the address of its storage by calling std​::​launder ([ptr.launder]).

— _end note_]

If a program ends the lifetime of an object of type T with static ([basic.stc.static]), thread ([basic.stc.thread]), or automatic ([basic.stc.auto]) storage duration and if T has a non-trivial destructor,23and another object of the original type does not occupy that same storage location when the implicit destructor call takes place, the behavior of the program is undefined.

This is true even if the block is exited with an exception.

[Example 4: class T { };struct B { ~B();};void h() { B b;new (&b) T;} — _end example_]

Creating a new object within the storage that a const, complete object with static, thread, or automatic storage duration occupies, or within the storage that such a const object used to occupy before its lifetime ended, results in undefined behavior.

[Example 5: struct B { B();~B();};const B b;void h() { b.~B();new (const_cast<B*>(&b)) const B; } — _end example_]

In this subclause, “before” and “after” refer to the “happens before” relation ([intro.multithread]).

[Note 6:

Therefore, undefined behavior results if an object that is being constructed in one thread is referenced from another thread without adequate synchronization.

— _end note_]