Lifetime - cppreference.com

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 an object begins when:

storage with the proper alignment and size for its type is obtained, and

its initialization (if any) is complete (including

default initialization

via no constructor or

trivial default constructor

), except that

if the object is a

union member

or subobject thereof, its lifetime only begins if that union member is the initialized member in the union, or it is made active,

if the object is nested in a union object, its lifetime may begin if the containing union object is assigned or constructed by a trivial special member function,

an array object's lifetime may also begin if it is allocated by

std::allocator::allocate

.

Some operations

implicitly create objects

of

implicit-lifetime types

in given region of storage and start their lifetime. If a subobject of an implicitly created object is not of an implicit-lifetime type, its lifetime does not begin implicitly.

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), 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.

Lifetime of an object is equal to or is nested within the lifetime of its storage, see

storage duration

.

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.

Lifetimes of non-static data members and base subobjects begin and end following

class initialization order

.

Temporary object lifetime

Temporary objects are created when a prvalue is

materialized

so that it can be used as a glvalue, which occurs(since C++17) in the following situations:

binding a reference to a prvalue

When an object of type T is passed to or returned from a

potentially-evaluated

function call, if T is one of the following types, implementations are permitted to create temporary objects to hold the function parameter or result object:

a class type satisfying all following conditions: T has at least one eligible

copy

or

move

constructor.

Each eligible copy/move constructor of T is trivial.

The

destructor

of T is either trivial or deleted.

The temporary object is constructed from the function argument or return value, respectively, and the function’s parameter or return object is initialized as if by using the eligible trivial constructor to copy the temporary (even if that constructor is inaccessible or would not be selected by overload resolution to perform a copy or move of the object).

(until C++26)The temporary objects are created as follows:

The first such temporary object is constructed from the function argument or return value, respectively.

Each successive temporary object is initialized from the previous one as if by

direct-initialization

if T is a scalar type, otherwise by using an eligible trivial constructor.

The function parameter or return object is initialized from the final temporary as if by direct initialization if T is a scalar type, otherwise by using an eligible trivial constructor.

In all cases, the eligible constructor is used even if that constructor is inaccessible or would not be selected by overload resolution to perform a copy or move of the object.

(since C++26)This latitude is granted to allow objects to be passed to or returned from functions in registers.

(since C++17)All temporary objects are destroyed as the last step in evaluating the

full-expression

that (lexically) contains the point where they were created, and if multiple temporary objects were created, they are destroyed in the order opposite to the order of creation. This is true even if that evaluation ends in throwing an exception.

There are the following exceptions from that:

The lifetime of a temporary object may be extended by binding to a reference, see

reference initialization

for details.

The lifetime of a temporary object created when evaluating the default arguments of a default or copy constructor used to initialize or copy an element of an array ends before the next element of the array begins initialization.

The lifetime of a temporary object created in a

structured binding

declaration (introduced by the initializer for a variable with unique name) is extended to the end of the structured binding declaration.

(since C++17)The lifetime of a temporary object created in the range-initializer of a

range-for

statement that would otherwise be destroyed at the end of the range-initializer is extended to the end of the loop body.

(since C++23)Storage reuse

A program may end an object's lifetime by explicitly invoking its destructor, and if the object has a

trivial destructor

, its lifetime may also be safely ended by deallocating the object's storage. However, if a program ends the lifetime of an object that is a variable explicitly, it must ensure that a new object of the same type is constructed in-place (e.g., via placement new) before the destructor may be called implicitly, i.e., due to scope exit or exception for automatic objects, due to thread exit for thread-local objects,(since C++11) or due to program exit for static objects; otherwise the behavior is undefined.

classT{};// trivialstructB{~B(){}// non-trivial};voidx(){longlongn;// automatic, trivialnew(&n)double(3.14);// reuse with a different type okay}// okayvoidh(){Bb;// automatic non-trivially destructibleb.~B();// end lifetime (not required, since no side-effects)new(&b)T;// wrong type: okay until the destructor is called}// destructor is called: undefined behaviorIt is undefined behavior to reuse storage that is or was occupied by a const complete object of static, thread-local,(since C++11) or automatic storage duration because such objects may be stored in read-only memory:

structB{B();// non-trivial~B();// non-trivial};constBb;// const staticvoidh(){b.~B();// end the lifetime of bnew(const_cast<B*>(&b))constB;// undefined behavior: attempted reuse of a const}When evaluating a

new expression

, storage is considered reused after it is returned from the

allocation function

, but before the evaluation of the initializer of the new expression:

structS{intm;};voidf(){Sx{1};new(&x)S(x.m);// undefined behavior: the storage is reused}If a new object is created at the address that was occupied by another object, then all pointers, references, and the name of the original object will automatically refer to the new object and, once the lifetime of the new object begins, can be used to manipulate the new object, but only if the original object is transparently replaceable by the new object.

If all following conditions are satisfied, object x is transparently replaceable by object y:

The storage for y exactly overlays the storage location which x occupied.

y is of the same type as x (ignoring the top-level cv-qualifiers).

x is not a complete const object.

Neither x nor y is a base class subobject, or a member subobject declared with [[

no_unique_address

]](since C++20).

One of the following conditions is satisfied:

x and y are both complete objects.

x and y are direct subobjects of objects ox and oy respectively, and ox is transparently replaceable by oy.

structC{inti;voidf();constC&operator=(constC&);};constC&C::operator=(constC&other){if(this!=&other){this->~C();// lifetime of *this endsnew(this)C(other);// new object of type C createdf();// well-defined}return*this;}Cc1;Cc2;c1=c2;// well-definedc1.f();// well-defined; c1 refers to a new object of type CIf the conditions listed above are not met, a valid pointer to the new object may still be obtained by applying the pointer optimization barrier

std::launder

:

structA{virtualinttransmogrify();};structB:A{inttransmogrify()override{::new(this)A;return2;}};inlineintA::transmogrify(){::new(this)B;return1;}voidtest(){Ai;intn=i.transmogrify();// int m = i.transmogrify(); // undefined behavior:// the new A object is a base subobject, while the old one is a complete objectintm=std::launder(&i)->transmogrify();// OKassert(m+n==3);}(since C++17)Similarly, if an object is created in the storage of a class member or array element, the created object is only a subobject (member or element) of the original object's containing object if:

the lifetime of the containing object has begun and not ended

the storage for the new object exactly overlays the storage of the original object

the new object is of the same type as the original object (ignoring cv-qualification).

Providing storage

As a special case, objects can be created in arrays of unsignedchar or

std::byte

(since C++17) (in which case it is said that the array provides storage for the object) if

the lifetime of the array has begun and not ended

the storage for the new object fits entirely within the array

there is no array object that satisfies these constraints nested within the array.

If that portion of the array previously provided storage for another object, the lifetime of that object ends because its storage was reused, however the lifetime of the array itself does not end (its storage is not considered to have been reused).

template<typename...T>structAlignedUnion{alignas(T...)unsignedchardata[max(sizeof(T)...)];};intf(){AlignedUnion<int,char>au;int*p=new(au.data)int;// OK, au.data provides storagechar*c=new(au.data)char();// OK, ends lifetime of *pchar*d=new(au.data+1)char();return*c+*d;// OK}Access outside of lifetime

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, the behaviors of the following uses of the glvalue expression that identifies that object are undefined, unless the object is being constructed or destructed (separate set of rules applies):

Lvalue to rvalue conversion (e.g. function call to a function that takes a value).

Access to a non-static data member or a call to a non-static member function.

Binding a reference to a virtual base class subobject.

dynamic_cast

or

typeid

expressions.

The above rules apply to pointers as well (binding a reference to virtual base is replaced by implicit conversion to a pointer to virtual base), with two additional rules:

static_cast

of a pointer to storage without an object is only allowed when casting to (possibly cv-qualified) void*.

Pointers to storage without an object that were cast to possibly cv-qualified void* can only be

static_cast

to pointers to possibly cv-qualified char, or possibly cv-qualified unsignedchar, or possibly cv-qualified

std::byte

(since C++17).

During construction and destruction it is generally allowed to call non-static member functions, access non-static data members, and use

typeid

and

dynamic_cast

. However, because the lifetime either has not begun yet (during construction) or has already ended (during destruction), only specific operations are allowed. For one restriction, see

virtual function calls during construction and destruction

.

Notes

Until the resolution of

CWG issue 2256

, the end of lifetime rules are different between non-class objects (end of storage duration) and class objects (reverse order of construction):

structA{int*p;~A(){std::cout<<*p;}// undefined behavior since CWG2256: n does not outlive a// well-defined until CWG2256: prints 123};voidf(){Aa;intn=123;// if n did not outlive a, this could have been optimized out (dead store)a.p=&n;}Until the resolution of

RU007

, a non-static member of a const-qualified type or a reference type prevents its containing object from being transparently replaceable, which makes

std::vector

and

std::deque

hard to implement:

structX{constintn;};unionU{Xx;floatf;};voidtong(){Uu={{1}};u.f=5.f;// OK: creates new subobject of 'u'X*p=new(&u.x)X{2};// OK: creates new subobject of 'u'assert(p->n==2);// OKassert(u.x.n==2);// undefined until RU007:// 'u.x' does not name the new subobjectassert(*std::launder(&u.x.n)==2);// OK even until RU007}Defect reports

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

DR Applied to Behavior as published Correct behavior

CWG 119

C++98 an object of a class type with a non-trivial constructor can
only start its lifetime when the constructor call has completed lifetime also started
for other initializations

CWG 201

C++98 lifetime of a temporary object in a default argument
of a default constructor was required to end
when the initialization of the array completes lifetime ends before
initializing the next
element (also resolves

CWG issue 124

)

CWG 274

C++98 an lvalue designating an out-of-lifetime object could be
used as the operand of static_cast only if the conversion
was ultimately to cv-unqualified char& or unsignedchar&cv-qualified char&
and unsignedchar&
also allowed

CWG 597

C++98 the following behaviors were undefined:
1. a pointer to an out-of-lifetime object is implicitly
converted to a pointer to a non-virtual base class
2. an lvalue referring to an out-of-lifetime object
is bound to a reference to a non-virtual base class
3. an lvalue referring to an out-of-lifetime object is used
as the operand of a static_cast (with a few exceptions) made well-defined

CWG 2012

C++98 lifetime of references was specified to match storage duration,
requiring that extern references are alive before their initializers run lifetime begins
at initialization

CWG 2107

C++98 the resolution of

CWG issue 124

was not applied to copy constructors applied

CWG 2256

C++98 lifetime of trivially destructible objects were inconsistent with other objects made consistent

CWG 2470

C++98 more than one arrays could provide storage for the same object only one provides

CWG 2489

C++98 char[] cannot provide storage, but objects
could be implicitly created within its storage objects cannot be
implicitly created within
the storage of char[]

CWG 2523

C++98 if a destructor is not invoked because of reusing storage and the
program depends on its side effects, the behavior was undefined the behavior is well-
defined in this case

CWG 2721

C++98 the exact time point of storage reuse was unclear for placement newmade clear

CWG 2849

C++23 function parameter objects were considered as temporary
objects for range-for loop temporary object lifetime extension not considered as
temporary objects

CWG 2854

C++98 exception objects were temporary objects they are not
temporary objects

CWG 2867

C++17 the lifetime of temporary objects created in
structured binding declarations were not extended extended to the end
of the declaration

P0137R1

C++98 creating an object in an array of unsignedchar reused its storage its storage is not reused

P0593R6

C++98 a pseudo-destructor call had no effects it destroys the object

P1971R0

C++98 a non-static data member of a const-qualified type or a reference type
prevented its containing object from being transparently replaceable restriction removed

P2103R0

C++98 transparently replaceability did not require keeping the original structure requires References

C++23 standard (ISO/IEC 14882:2024):

6.7.3 Object lifetime [basic.life]

11.9.5 Construction and destruction [class.cdtor]

C++20 standard (ISO/IEC 14882:2020):

6.7.3 Object lifetime [basic.life]

11.10.4 Construction and destruction [class.cdtor]

C++17 standard (ISO/IEC 14882:2017):

6.8 Object lifetime [basic.life]

15.7 Construction and destruction [class.cdtor]

C++14 standard (ISO/IEC 14882:2014):

3 Object lifetime [basic.life]

12.7 Construction and destruction [class.cdtor]

C++11 standard (ISO/IEC 14882:2011):

3.8 Object lifetime [basic.life]

12.7 Construction and destruction [class.cdtor]

C++03 standard (ISO/IEC 14882:2003):

3.8 Object lifetime [basic.life]

12.7 Construction and destruction [class.cdtor]

C++98 standard (ISO/IEC 14882:1998):

3.8 Object lifetime [basic.life]

12.7 Construction and destruction [class.cdtor]

See also