General topics | ||||||||||||||||
Flow control | ||||||||||||||||
Conditional execution statements | ||||||||||||||||
Iteration statements (loops) | ||||||||||||||||
Jump statements | ||||||||||||||||
Functions | ||||||||||||||||
Function declaration | ||||||||||||||||
Lambda function expression | ||||||||||||||||
inline specifier | ||||||||||||||||
Dynamic exception specifications(until C++17*) | ||||||||||||||||
noexcept specifier(C++11) | ||||||||||||||||
Exceptions | ||||||||||||||||
Namespaces | ||||||||||||||||
Types | ||||||||||||||||
Specifiers | ||||||||||||||||
| ||||||||||||||||
Storage duration specifiers | ||||||||||||||||
Initialization | ||||||||||||||||
Expressions | ||||||||||||||||
Alternative representations | ||||||||||||||||
Literals | ||||||||||||||||
Boolean -Integer -Floating-point | ||||||||||||||||
Character -String -nullptr(C++11) | ||||||||||||||||
User-defined(C++11) | ||||||||||||||||
Utilities | ||||||||||||||||
Attributes(C++11) | ||||||||||||||||
Types | ||||||||||||||||
typedef declaration | ||||||||||||||||
Type alias declaration(C++11) | ||||||||||||||||
Casts | ||||||||||||||||
Memory allocation | ||||||||||||||||
Classes | ||||||||||||||||
Class-specific function properties | ||||||||||||||||
| ||||||||||||||||
Special member functions | ||||||||||||||||
Templates | ||||||||||||||||
Miscellaneous | ||||||||||||||||
Everyobject andreference has alifetime, 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:
Some operationsimplicitly create objects ofimplicit-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:
Lifetime of an object is equal to or is nested within the lifetime of its storage, seestorage duration.
The lifetime of areference 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 makesdangling references possible.
Lifetimes of non-static data members and base subobjects begin and end followingclass initialization order.
Contents |
Temporary objects are createdwhen a prvalue ismaterialized so that it can be used as a glvalue, which occurs(since C++17) in the following situations:
| (since C++11) |
| (until C++17) | ||
The materialization of a temporary object is generally delayed as long as possible in order to avoid creating unnecessary temporary object: seecopy elision. | (since C++17) |
When an object of type
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 thefull-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:
| (since C++17) |
| (since C++23) |
A program is not required to call the destructor of an object to end its lifetime if the object istrivially-destructible (be careful that the correct behavior of the program may depend on the destructor). However, if a program ends the lifetime of a non-trivially destructible object that is a variable explicitly, it must ensure that a new object of the same type is constructed in-place (e.g. via placementnew) 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.
class T{};// trivial struct B{ ~B(){}// non-trivial}; void x(){longlong n;// automatic, trivial new(&n)double(3.14);// reuse with a different type okay}// okay void h(){ B b;// automatic non-trivially destructible b.~B();// end lifetime (not required, since no side-effects) new(&b) T;// wrong type: okay until the destructor is called}// destructor is called: undefined behavior
It 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:
struct B{ B();// non-trivial ~B();// non-trivial};const B b;// const static void h(){ b.~B();// end the lifetime of b new(const_cast<B*>(&b))const B;// undefined behavior: attempted reuse of a const}
When evaluating anew expression, storage is considered reused after it is returned from theallocation function, but before the evaluation of theinitializer of the new expression:
struct S{int m;}; void f(){ S x{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, objectx istransparently replaceable by objecty:
[[no_unique_address]]
(since C++20).struct C{int i;void f();const C& operator=(const C&);}; const C& C::operator=(const C& other){if(this!=&other){ this->~C();// lifetime of *this ends new(this) C(other);// new object of type C created f();// well-defined}return*this;} C c1;C c2;c1= c2;// well-definedc1.f();// well-defined; c1 refers to a new object of type C
If the conditions listed above are not met, a valid pointer to the new object may still be obtained by applying the pointer optimization barrierstd::launder: struct A{virtualint transmogrify();}; struct B: A{int transmogrify() override{::new(this) A;return2;}}; inlineint A::transmogrify(){::new(this) B;return1;} void test(){ A i;int n= i.transmogrify();// int m = i.transmogrify(); // undefined behavior:// the new A object is a base subobject, while the old one is a complete objectint m=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:
Otherwise, the name of the original subobject cannot be used to access the new object withoutstd::launder:
| (since C++17) |
As a special case, objects can be created in arrays ofunsignedchar orstd::byte(since C++17) (in which case it is said that the arrayprovides storage for the object) if
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>struct AlignedUnion{ alignas(T...)unsignedchar data[max(sizeof(T)...)];}; int f(){ 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}
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):
dynamic_cast
ortypeid
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*.static_cast
to pointers to possibly cv-qualifiedchar, or possibly cv-qualifiedunsignedchar, or possibly cv-qualifiedstd::byte(since C++17).During construction and destruction it is generally allowed to call non-static member functions, access non-static data members, and usetypeid
anddynamic_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, seevirtual function calls during construction and destruction.
Until the resolution ofCWG issue 2256, the end of lifetime rules are different between non-class objects (end of storage duration) and class objects (reverse order of construction):
struct A{int* p; ~A(){std::cout<<*p;}// undefined behavior since CWG2256: n does not outlive a// well-defined until CWG2256: prints 123}; void f(){ A a;int n=123;// if n did not outlive a, this could have been optimized out (dead store) a.p=&n;}
Until the resolution ofRU007, a non-static member of a const-qualified type or a reference type prevents its containing object from being transparently replaceable, which makesstd::vector andstd::deque hard to implement:
struct X{constint n;};union U{ X x;float f;}; void tong(){ U u={{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}
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-unqualifiedchar& orunsignedchar& | cv-qualifiedchar& andunsignedchar& 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 astatic_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 ofCWG 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 ofchar[] |
CWG 2527 | 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 placementnew | made 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 ofunsignedchar 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 |
C documentation forLifetime |