6 Basic concepts [basic]

6.7 Storage duration [basic.stc]

The storage duration is the property of an object that defines the minimum potential lifetime of the storage containing the object. The storage duration is determined by the construct used to create the object and is one of the following:

Static, thread, and automatic storage durations are associated with objects introduced by declarations ([basic.def]) and implicitly created by the implementation. The dynamic storage duration is associated with objects created by a new-expression.

The storage duration categories apply to references as well.

When the end of the duration of a region of storage is reached, the values of all pointers representing the address of any part of that region of storage become invalid pointer values. Indirection through an invalid pointer value and passing an invalid pointer value to a deallocation function have undefined behavior. Any other use of an invalid pointer value has implementation-defined behavior.37

Some implementations might define that copying an invalid pointer value causes a system-generated runtime fault.

6.7.1 Static storage duration [basic.stc.static]

All variables which do not have dynamic storage duration, do not have thread storage duration, and are not local have static storage duration. The storage for these entities shall last for the duration of the program ([basic.start.static], [basic.start.term]).

If a variable with static storage duration has initialization or a destructor with side effects, it shall not be eliminated even if it appears to be unused, except that a class object or its copy/move may be eliminated as specified in [class.copy].

The keyword static can be used to declare a local variable with static storage duration. [Note: [stmt.dcl] describes the initialization of local static variables; [basic.start.term] describes the destruction of local static variables. end note]

The keyword static applied to a class data member in a class definition gives the data member static storage duration.

6.7.2 Thread storage duration [basic.stc.thread]

All variables declared with the thread_­local keyword have thread storage duration. The storage for these entities shall last for the duration of the thread in which they are created. There is a distinct object or reference per thread, and use of the declared name refers to the entity associated with the current thread.

A variable with thread storage duration shall be initialized before its first odr-use and, if constructed, shall be destroyed on thread exit.

6.7.3 Automatic storage duration [basic.stc.auto]

Block-scope variables not explicitly declared static, thread_­local, or extern have automatic storage duration. The storage for these entities lasts until the block in which they are created exits.

[Note: These variables are initialized and destroyed as described in [stmt.dcl]. end note]

If a variable with automatic storage duration has initialization or a destructor with side effects, an implementation shall not destroy it before the end of its block nor eliminate it as an optimization, even if it appears to be unused, except that a class object or its copy/move may be eliminated as specified in [class.copy].

6.7.4 Dynamic storage duration [basic.stc.dynamic]

Objects can be created dynamically during program execution, using new-expressions, and destroyed using delete-expressions. A C++ implementation provides access to, and management of, dynamic storage via the global allocation functions operator new and operator new[] and the global deallocation functions operator delete and operator delete[]. [Note: The non-allocating forms described in [new.delete.placement] do not perform allocation or deallocation. end note]

The library provides default definitions for the global allocation and deallocation functions. Some global allocation and deallocation functions are replaceable ([new.delete]). A C++ program shall provide at most one definition of a replaceable allocation or deallocation function. Any such function definition replaces the default version provided in the library ([replacement.functions]). The following allocation and deallocation functions ([support.dynamic]) are implicitly declared in global scope in each translation unit of a program.

void* operator new(std::size_t);
void* operator new(std::size_t, std::align_val_t);

void operator delete(void*) noexcept;
void operator delete(void*, std::size_t) noexcept;
void operator delete(void*, std::align_val_t) noexcept;
void operator delete(void*, std::size_t, std::align_val_t) noexcept;

void* operator new[](std::size_t);
void* operator new[](std::size_t, std::align_val_t);

void operator delete[](void*) noexcept;
void operator delete[](void*, std::size_t) noexcept;
void operator delete[](void*, std::align_val_t) noexcept;
void operator delete[](void*, std::size_t, std::align_val_t) noexcept;

These implicit declarations introduce only the function names operator new, operator new[], operator delete, and operator delete[]. [Note: The implicit declarations do not introduce the names std, std​::​size_­t, std​::​align_­val_­t, or any other names that the library uses to declare these names. Thus, a new-expression, delete-expression or function call that refers to one of these functions without including the header <new> is well-formed. However, referring to std or std​::​size_­t or std​::​align_­val_­t is ill-formed unless the name has been declared by including the appropriate header. end note] Allocation and/or deallocation functions may also be declared and defined for any class ([class.free]).

Any allocation and/or deallocation functions defined in a C++ program, including the default versions in the library, shall conform to the semantics specified in [basic.stc.dynamic.allocation] and [basic.stc.dynamic.deallocation].

6.7.4.1 Allocation functions [basic.stc.dynamic.allocation]

An allocation function shall be a class member function or a global function; a program is ill-formed if an allocation function is declared in a namespace scope other than global scope or declared static in global scope. The return type shall be void*. The first parameter shall have type std​::​size_­t ([support.types]). The first parameter shall not have an associated default argument. The value of the first parameter shall be interpreted as the requested size of the allocation. An allocation function can be a function template. Such a template shall declare its return type and first parameter as specified above (that is, template parameter types shall not be used in the return type and first parameter type). Template allocation functions shall have two or more parameters.

The allocation function attempts to allocate the requested amount of storage. If it is successful, it shall return the address of the start of a block of storage whose length in bytes shall be at least as large as the requested size. There are no constraints on the contents of the allocated storage on return from the allocation function. The order, contiguity, and initial value of storage allocated by successive calls to an allocation function are unspecified. The pointer returned shall be suitably aligned so that it can be converted to a pointer to any suitable complete object type ([new.delete.single]) and then used to access the object or array in the storage allocated (until the storage is explicitly deallocated by a call to a corresponding deallocation function). Even if the size of the space requested is zero, the request can fail. If the request succeeds, the value returned shall be a non-null pointer value ([conv.ptr]) p0 different from any previously returned value p1, unless that value p1 was subsequently passed to an operator delete. Furthermore, for the library allocation functions in [new.delete.single] and [new.delete.array], p0 shall represent the address of a block of storage disjoint from the storage for any other object accessible to the caller. The effect of indirecting through a pointer returned as a request for zero size is undefined.38

An allocation function that fails to allocate storage can invoke the currently installed new-handler function ([new.handler]), if any. [Note: A program-supplied allocation function can obtain the address of the currently installed new_­handler using the std​::​get_­new_­handler function ([set.new.handler]). end note] If an allocation function that has a non-throwing exception specification fails to allocate storage, it shall return a null pointer. Any other allocation function that fails to allocate storage shall indicate failure only by throwing an exception of a type that would match a handler of type std​::​bad_­alloc.

A global allocation function is only called as the result of a new expression, or called directly using the function call syntax, or called indirectly through calls to the functions in the C++ standard library. [Note: In particular, a global allocation function is not called to allocate storage for objects with static storage duration, for objects or references with thread storage duration, for objects of type std​::​type_­info, or for an exception object. end note]

The intent is to have operator new() implementable by calling std​::​malloc() or std​::​calloc(), so the rules are substantially the same. C++ differs from C in requiring a zero request to return a non-null pointer.

6.7.4.2 Deallocation functions [basic.stc.dynamic.deallocation]

Deallocation functions shall be class member functions or global functions; a program is ill-formed if deallocation functions are declared in a namespace scope other than global scope or declared static in global scope.

Each deallocation function shall return void and its first parameter shall be void*. A deallocation function may have more than one parameter. A usual deallocation function is a deallocation function that has:

  • exactly one parameter; or

  • exactly two parameters, the type of the second being either std​::​align_­val_­t or std​::​size_­t39; or

  • exactly three parameters, the type of the second being std​::​size_­t and the type of the third being std​::​align_­val_­t.

A deallocation function may be an instance of a function template. Neither the first parameter nor the return type shall depend on a template parameter. [Note: That is, a deallocation function template shall have a first parameter of type void* and a return type of void (as specified above). end note] A deallocation function template shall have two or more function parameters. A template instance is never a usual deallocation function, regardless of its signature.

If a deallocation function terminates by throwing an exception, the behavior is undefined. The value of the first argument supplied to a deallocation function may be a null pointer value; if so, and if the deallocation function is one supplied in the standard library, the call has no effect.

If the argument given to a deallocation function in the standard library is a pointer that is not the null pointer value, the deallocation function shall deallocate the storage referenced by the pointer, ending the duration of the region of storage.

The global operator delete(void*, std​::​size_­t) precludes use of an allocation function void operator new(std​::​size_­t, std​::​size_­t) as a placement allocation function ([diff.cpp11.basic]).

6.7.4.3 Safely-derived pointers [basic.stc.dynamic.safety]

A traceable pointer object is

  • an object of an object pointer type, or

  • an object of an integral type that is at least as large as std​::​intptr_­t, or

  • a sequence of elements in an array of narrow character type, where the size and alignment of the sequence match those of some object pointer type.

A pointer value is a safely-derived pointer to a dynamic object only if it has an object pointer type and it is one of the following:

  • the value returned by a call to the C++ standard library implementation of ​::​operator new(std​::​​size_­t) or ​::​operator new(std​::​size_­t, std​::​align_­val_­t);40

  • the result of taking the address of an object (or one of its subobjects) designated by an lvalue resulting from indirection through a safely-derived pointer value;

  • the result of well-defined pointer arithmetic ([expr.add]) using a safely-derived pointer value;

  • the result of a well-defined pointer conversion ([conv.ptr], [expr.cast]) of a safely-derived pointer value;

  • the result of a reinterpret_­cast of a safely-derived pointer value;

  • the result of a reinterpret_­cast of an integer representation of a safely-derived pointer value;

  • the value of an object whose value was copied from a traceable pointer object, where at the time of the copy the source object contained a copy of a safely-derived pointer value.

An integer value is an integer representation of a safely-derived pointer only if its type is at least as large as std​::​intptr_­t and it is one of the following:

  • the result of a reinterpret_­cast of a safely-derived pointer value;

  • the result of a valid conversion of an integer representation of a safely-derived pointer value;

  • the value of an object whose value was copied from a traceable pointer object, where at the time of the copy the source object contained an integer representation of a safely-derived pointer value;

  • the result of an additive or bitwise operation, one of whose operands is an integer representation of a safely-derived pointer value P, if that result converted by reinterpret_­cast<void*> would compare equal to a safely-derived pointer computable from reinterpret_­cast<void*>(P).

An implementation may have relaxed pointer safety, in which case the validity of a pointer value does not depend on whether it is a safely-derived pointer value. Alternatively, an implementation may have strict pointer safety, in which case a pointer value referring to an object with dynamic storage duration that is not a safely-derived pointer value is an invalid pointer value unless the referenced complete object has previously been declared reachable ([util.dynamic.safety]). [Note: The effect of using an invalid pointer value (including passing it to a deallocation function) is undefined, see [basic.stc.dynamic.deallocation]. This is true even if the unsafely-derived pointer value might compare equal to some safely-derived pointer value. end note] It is implementation-defined whether an implementation has relaxed or strict pointer safety.

This section does not impose restrictions on indirection through pointers to memory not allocated by ​::​operator new. This maintains the ability of many C++ implementations to use binary libraries and components written in other languages. In particular, this applies to C binaries, because indirection through pointers to memory allocated by std​::​malloc is not restricted.

6.7.5 Duration of subobjects [basic.stc.inherit]

The storage duration of subobjects and reference members is that of their complete object ([intro.object]).