|
|
|
... = this;
// OK, this points to valid memory
}
void g() {
void* p = std::malloc(sizeof(D1) + sizeof(D2));
B* pb = new (p) D1;
pb->mutate();
*pb;
// OK: pb points to valid memory
void* q = pb;
// OK: pb points to valid memory
pb->f();
// undefined behavior, lifetime of *pb has ended
}
— end example ]
7
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 15.7. Otherwise, such a glvalue refers to allocated
storage (6.6.4.4.1), and using the properties of the glvalue that do not depend on its value is well-defined.
The program has undefined behavior if:
(7.1)
—
the glvalue is used to access the object, or
(7.2)
—
the glvalue is used to call a non-static member function of the object, or
(7.3)
—
the glvalue is bound to a reference to a virtual base class (11.6.3), or
(7.4)
—
the glvalue is used as the operand of a dynamic_cast (8.5.1.7) or as the operand of typeid.
8
If, after the lifetime of an object has ended and before the storage which the object occupied is reused or
released, a new object is created at the storage location which the original object occupied, 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, if:
(8.1)
—
the storage for the new object exactly overlays the storage location which the original object occupied,
and
(8.2)
—
the new object is of the same type as the original object (ignoring the top-level cv-qualifiers), and
(8.3)
—
the type of the original object is not const-qualified, and, if a class type, does not contain any non-static
data member whose type is const-qualified or a reference type, and
(8.4)
—
the original object was a most derived object (6.6.2) of type T and the new object is a most derived
object of type T (that is, they are not base class subobjects).
[ Example:
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-defined
c1.f();
// well-defined; c1 refers to a new object of type C
— end example ] [ Note: 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 (21.6).
— end note ]
§ 6.6.3
52
9
If a program ends the lifetime of an object of type T with static (6.6.4.1), thread (6.6.4.2), or automatic (6.6.4.3)
storage duration and if T has a non-trivial destructor,34 the program must ensure that an object of the
original type occupies that same storage location when the implicit destructor call takes place; otherwise the
behavior of the program is undefined. This is true even if the block is exited with an exception. [ Example:
class T { };
struct B {
~B();
};
void h() {
B b;
new (&b) T;
}
// undefined behavior at block exit
— end example ]
10
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:
struct B {
B();
~B();
};
const B b;
void h() {
b.~B();
new (const_cast<B*>(&b)) const B;
// undefined behavior
}
— end example ]
11
In this subclause, “before” and “after” refer to the “happens before” relation (6.8.2).
[Note: Therefore,
undefined behavior results if an object that is being constructed in one thread is referenced from another
thread without adequate synchronization.
— end note ]
6.6.4
Storage duration
[basic.stc]
1
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:
(1.1)
—
static storage duration
(1.2)
—
thread storage duration
(1.3)
—
automatic storage duration
(1.4)
—
dynamic storage duration
2
Static, thread, and automatic storage durations are associated with objects introduced by declarations (6.1)
and implicitly created by the implementation (15.2). The dynamic storage duration is associated with objects
created by a new-expression (8.5.2.4).
3
The storage duration categories apply to references as well.
4
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 (6.7.2). 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.35
34) That is, an object for which a destructor will be called implicitly—upon exit from the block for an object with automatic
storage duration, upon exit from the thread for an object with thread storage duration, or upon exit from the program for an
object with static storage duration.
35) Some implementations might define that copying an invalid pointer value causes a system-generated runtime fault.
§ 6.6.4
53
6.6.4.1
Static storage duration
[basic.stc.static]
1
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 (6.8.3.2, 6.8.3.4).
2
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 15.8.
3
The keyword static can be used to declare a local variable with static storage duration. [ Note: 9.7 describes
the initialization of local static variables; 6.8.3.4 describes the destruction of local static variables.
— end
note ]
4
The keyword static applied to a class data member in a class definition gives the data member static storage
duration.
6.6.4.2
Thread storage duration
[basic.stc.thread]
1
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.
2
A variable with thread storage duration shall be initialized before its first odr-use (6.2) and, if constructed,
shall be destroyed on thread exit.
6.6.4.3
Automatic storage duration
[basic.stc.auto]
1
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.
2
[ Note: These variables are initialized and destroyed as described in 9.7.
— end note ]
3
If a variable with automatic storage duration has initialization or a destructor with side effects, an implemen-
tation 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 15.8.
6.6.4.4
Dynamic storage duration
[basic.stc.dynamic]
1
Objects can be created dynamically during program execution (6.8.1), using new-expressions (8.5.2.4), and
destroyed using delete-expressions (8.5.2.5). 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 21.6.2.3 do not perform allocation or deallocation.
— end note ]
2
The library provides default definitions for the global allocation and deallocation functions. Some global
allocation and deallocation functions are replaceable (21.6.2). 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 (20.5.4.6). The following allocation and deallocation functions (21.6)
are implicitly declared in global scope in each translation unit of a program.
[[nodiscard]] void* operator new(std::size_t);
[[nodiscard]] 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;
[[nodiscard]] void* operator new[](std::size_t);
[[nodiscard]] 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[], opera-
tor delete, and operator delete[]. [ Note: The implicit declarations do not introduce the names std,
§ 6.6.4.4
54
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 (15.5).
3
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 6.6.4.4.1 and 6.6.4.4.2.
6.6.4.4.1
Allocation functions
[basic.stc.dynamic.allocation]
1
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 (21.2). The first
parameter shall not have an associated default argument (11.3.6). 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.
2
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 (21.6.2.1) 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 (7.11) 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 21.6.2.1
and 21.6.2.2, 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.36
3
An allocation function that fails to allocate storage can invoke the currently installed new-handler function
(21.6.3.3), 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 (21.6.3.4).
— end note ] If an allocation
function that has a non-throwing exception specification (18.4) 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 (18.1) of a type that would match a handler (18.3) of type std::bad_alloc (21.6.3.1).
4
A global allocation function is only called as the result of a new expression (8.5.2.4), or called directly using
the function call syntax (8.5.1.2), 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 (6.6.4.1), for objects or references with thread storage duration (6.6.4.2), for objects
of type std::type_info (8.5.1.8), or for an exception object (18.1).
— end note ]
6.6.4.4.2
Deallocation functions
[basic.stc.dynamic.deallocation]
1
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.
2
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:
(2.1)
—
exactly one parameter; or
(2.2)
—
exactly two parameters, the type of the second being either std::align_val_t or std::size_t37; or
(2.3)
—
exactly three parameters, the type of the second being std::size_t and the type of the third being
std::align_val_t.
36) The intent is to have operator new() implementable by calling std::malloc() or std::calloc(), so the rules are substan-
tially the same. C++ differs from C in requiring a zero request to return a non-null pointer.
37) 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 (C.3.2).
§ 6.6.4.4.2
55
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.
3
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.
4
If the argument given to a deallocation function in the standard library is a pointer that is not the null
pointer value (7.11), the deallocation function shall deallocate the storage referenced by the pointer, ending
the duration of the region of storage.
6.6.4.4.3
Safely-derived pointers
[basic.stc.dynamic.safety]
1
A traceable pointer object is
(1.1)
—
an object of an object pointer type (6.7.2), or
(1.2)
—
an object of an integral type that is at least as large as std::intptr_t, or
(1.3)
—
a sequence of elements in an array of narrow character type (6.7.1), where the size and alignment of
the sequence match those of some object pointer type.
2
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:
(2.1)
—
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);38
(2.2)
—
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;
(2.3)
—
the result of well-defined pointer arithmetic (8.5.6) using a safely-derived pointer value;
(2.4)
—
the result of a well-defined pointer conversion (7.11, 8.5.3) of a safely-derived pointer value;
(2.5)
—
the result of a reinterpret_cast of a safely-derived pointer value;
(2.6)
—
the result of a reinterpret_cast of an integer representation of a safely-derived pointer value;
(2.7)
—
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.
3
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:
(3.1)
—
the result of a reinterpret_cast of a safely-derived pointer value;
(3.2)
—
the result of a valid conversion of an integer representation of a safely-derived pointer value;
—
(3.3)
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;
—
(3.4)
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).
4
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 (23.10.5). [ Note: The effect of using an invalid pointer value (including passing it to
a deallocation function) is undefined, see 6.6.4. 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.
38) This subclause 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.6.4.4.3
56
6.6.4.5
Duration of subobjects
[basic.stc.inherit]
1
The storage duration of subobjects and reference members is that of their complete object (6.6.2).
6.6.5
Alignment
[basic.align]
1
Object types have alignment requirements (6.7.1, 6.7.2) which place restrictions on the addresses at which an
object of that type may be allocated. An alignment is an implementation-defined integer value representing
the number of bytes between successive addresses at which a given object can be allocated. An object type
imposes an alignment requirement on every object of that type; stricter alignment can be requested using the
alignment specifier (10.6.2).
2
A fundamental alignment is represented by an alignment less than or equal to the greatest alignment supported
by the implementation in all contexts, which is equal to alignof(std::max_align_t) (21.2). The alignment
required for a type might be different when it is used as the type of a complete object and when it is used as
the type of a subobject. [ Example:
struct B { long double d; };
struct D : virtual B { char c; };
When D is the type of a complete object, it will have a subobject of type B, so it must be aligned appropriately
for a long double. If D appears as a subobject of another object that also has B as a virtual base class, the
B subobject might be part of a different subobject, reducing the alignment requirements on the D subobject.
— end example ] The result of the alignof operator reflects the alignment requirement of the type in the
complete-object case.
3
An extended alignment is represented by an alignment greater than alignof(std::max_align_t). It is
implementation-defined whether any extended alignments are supported and the contexts in which they
are supported (10.6.2). A type having an extended alignment requirement is an over-aligned type. [Note:
Every over-aligned type is or contains a class type to which extended alignment applies (possibly through a
non-static data member).
— end note ] A new-extended alignment is represented by an alignment greater
than __STDCPP_DEFAULT_NEW_ALIGNMENT__ (19.8).
4
Alignments are represented as values of the type std::size_t. Valid alignments include only those values
returned by an alignof expression for the fundamental types plus an additional implementation-defined set
of values, which may be empty. Every alignment value shall be a non-negative integral power of two.
5
Alignments have an order from weaker to stronger or stricter alignments. Stricter alignments have larger
alignment values. An address that satisfies an alignment requirement also satisfies any weaker valid alignment
requirement.
6
The alignment requirement of a complete type can be queried using an alignof expression (8.5.2.6).
Furthermore, the narrow character types (6.7.1) shall have the weakest alignment requirement. [ Note: This
enables the narrow character types to be used as the underlying type for an aligned memory area (10.6.2). —
end note ]
7
Comparing alignments is meaningful and provides the obvious results:
(7.1)
—
Two alignments are equal when their numeric values are equal.
(7.2)
—
Two alignments are different when their numeric values are not equal.
(7.3)
—
When an alignment is larger than another it represents a stricter alignment.
8
[ Note: The runtime pointer alignment function (23.10.6) can be used to obtain an aligned pointer within a
buffer; the aligned-storage templates in the library (23.15.7.6) can be used to obtain aligned storage.
— end
note ]
9
If a request for a specific extended alignment in a specific context is not supported by an implementation,
the program is ill-formed.
6.7
Types
[basic.types]
1
[ Note: 6.7 and the subclauses thereof impose requirements on implementations regarding the representation of
types. There are two kinds of types: fundamental types and compound types. Types describe objects (6.6.2),
references (11.3.2), or functions (11.3.5).
— end note ]
2
For any object (other than a base-class subobject) of trivially copyable type T, whether or not the object
holds a valid value of type T, the underlying bytes (6.6.1) making up the object can be copied into an array of
§ 6.7
57
char, unsigned char, or std::byte (21.2.1).39 If the content of that array is copied back into the object,
the object shall subsequently hold its original value. [ Example:
#define N sizeof(T)
char buf[N];
T obj;
// obj initialized to its original value
std::memcpy(buf, &obj, N);
// between these two calls to std::memcpy, obj might be modified
std::memcpy(&obj, buf, N);
// at this point, each subobject of obj of scalar type holds its original value
— end example ]
3
For any trivially copyable type T, if two pointers to T point to distinct T objects obj1 and obj2, where
neither obj1 nor obj2 is a base-class subobject, if the underlying bytes (6.6.1) making up obj1 are copied
into obj2,40 obj2 shall subsequently hold the same value as obj1. [ Example:
T* t1p;
T* t2p;
// provided that t2p points to an initialized object ...
std::memcpy(t1p, t2p, sizeof(T));
// at this point, every subobject of trivially copyable type in *t1p contains
// the same value as the corresponding subobject in *t2p
— end example ]
4
The object representation of an object of type T is the sequence of N unsigned char objects taken up by the
object of type T, where N equals sizeof(T). The value representation of an object is the set of bits that
hold the value of type T. Bits in the object representation that are not part of the value representation are
padding bits. For trivially copyable types, the value representation is a set of bits in the object representation
that determines a value, which is one discrete element of an implementation-defined set of values.41
5
A class that has been declared but not defined, an enumeration type in certain contexts (10.2), or an array of
unknown bound or of incomplete element type, is an incompletely-defined object type.42 Incompletely-defined
object types and cv void are incomplete types (6.7.1). Objects shall not be defined to have an incomplete
type.
6
A class type (such as “class X”) might be incomplete at one point in a translation unit and complete later
on; the type “class X” is the same type at both points. The declared type of an array object might be
an array of incomplete class type and therefore incomplete; if the class type is completed later on in the
translation unit, the array type becomes complete; the array type at those two points is the same type. The
declared type of an array object might be an array of unknown bound and therefore be incomplete at one
point in a translation unit and complete later on; the array types at those two points (“array of unknown
bound of T” and “array of N T”) are different types. The type of a pointer to array of unknown bound, or of
a type defined by a typedef declaration to be an array of unknown bound, cannot be completed. [ Example:
class X;
// X is an incomplete type
extern X* xp;
// xp is a pointer to an incomplete type
extern int arr[];
// the type of arr is incomplete
typedef int UNKA[];
// UNKA is an incomplete type
UNKA* arrp;
// arrp is a pointer to an incomplete type
UNKA** arrpp;
void foo() {
xp++;
// ill-formed: X is incomplete
arrp++;
// ill-formed: incomplete type
arrpp++;
// OK: sizeof UNKA* is known
}
struct X { int i; };
// now X is a complete type
int arr[10];
// now the type of arr is complete
X x;
void bar() {
xp = &x;
// OK; type is “pointer to X”
39) By using, for example, the library functions (20.5.1.2) std::memcpy or std::memmove.
40) By using, for example, the library functions (20.5.1.2) std::memcpy or std::memmove.
41) The intent is that the memory model of C++ is compatible with that of ISO/IEC 9899 Programming Language C.
42) The size and layout of an instance of an incompletely-defined object type is unknown.
§ 6.7
58
arrp = &arr;
// ill-formed: different types
xp++;
// OK: X is complete
arrp++;
// ill-formed: UNKA can’t be completed
}
— end example ]
7
[ Note: The rules for declarations and expressions describe in which contexts incomplete types are prohibited.
— end note ]
8
An object type is a (possibly cv-qualified) type that is not a function type, not a reference type, and not
cv void.
9
Arithmetic types (6.7.1), enumeration types, pointer types, pointer-to-member types (6.7.2), std::nullptr_t,
and cv-qualified (6.7.3) versions of these types are collectively called scalar types. Cv-unqualified scalar types,
trivially copyable class types (Clause 12), arrays of such types, and cv-qualified versions of these types are
collectively called trivially copyable types. Scalar types, trivial class types (Clause 12), arrays of such types
and cv-qualified versions of these types are collectively called trivial types. Scalar types, standard-layout
class types (Clause 12), arrays of such types and cv-qualified versions of these types are collectively called
standard-layout types.
10
A type is a literal type if it is:
(10.1)
—
possibly cv-qualified void; or
(10.2)
—
a scalar type; or
(10.3)
—
a reference type; or
(10.4)
—
an array of literal type; or
(10.5)
—
a possibly cv-qualified class type (Clause 12) that has all of the following properties:
(10.5.1)
—
it has a trivial destructor,
(10.5.2)
—
it is either a closure type (8.4.5.1), an aggregate type (11.6.1), or has at least one constexpr
constructor or constructor template (possibly inherited (10.3.3) from a base class) that is not a
copy or move constructor,
(10.5.3)
—
if it is a union, at least one of its non-static data members is of non-volatile literal type, and
(10.5.4)
—
if it is not a union, all of its non-static data members and base classes are of non-volatile literal
types.
[ Note: A literal type is one for which it might be possible to create an object within a constant expression.
It is not a guarantee that it is possible to create such an object, nor is it a guarantee that any object of that
type will be usable in a constant expression.
— end note ]
11
Two types cv1 T1 and cv2 T2 are layout-compatible types if T1 and T2 are the same type, layout-compatible
enumerations (10.2), or layout-compatible standard-layout class types (12.2).
6.7.1
Fundamental types
[basic.fundamental]
1
Objects declared as characters (char) shall be large enough to store any member of the implementation’s basic
character set. If a character from this set is stored in a character object, the integral value of that character
object is equal to the value of the single character literal form of that character. It is implementation-defined
whether a char object can hold negative values. Characters can be explicitly declared unsigned or signed.
Plain char, signed char, and unsigned char are three distinct types, collectively called narrow character
types. A char, a signed char, and an unsigned char occupy the same amount of storage and have the
same alignment requirements (6.6.5); that is, they have the same object representation. For narrow character
types, all bits of the object representation participate in the value representation. [ Note: A bit-field of narrow
character type whose length is larger than the number of bits in the object representation of that type has
padding bits; see 6.7.
— end note ] For unsigned narrow character types, each possible bit pattern of the
value representation represents a distinct number. These requirements do not hold for other types. In any
particular implementation, a plain char object can take on either the same values as a signed char or an
unsigned char; which one is implementation-defined. For each value i of type unsigned char in the range
0 to 255 inclusive, there exists a value j of type char such that the result of an integral conversion (7.8) from
i to char is j, and the result of an integral conversion from j to unsigned char is i.
2
There are five standard signed integer types : “signed char”, “short int”, “int”, “long int”, and “long
long int”. In this list, each type provides at least as much storage as those preceding it in the list. There
§ 6.7.1
59
may also be implementation-defined extended signed integer types. The standard and extended signed integer
types are collectively called signed integer types. Plain ints have the natural size suggested by the architecture
of the execution environment43; the other signed integer types are provided to meet special needs.
3
For each of the standard signed integer types, there exists a corresponding (but different) standard un-
signed integer type:
“unsigned char”, “unsigned short int”, “unsigned int”, “unsigned long int”,
and “unsigned long long int”, each of which occupies the same amount of storage and has the same
alignment requirements (6.6.5) as the corresponding signed integer type44; that is, each signed integer type
has the same object representation as its corresponding unsigned integer type. Likewise, for each of the
extended signed integer types there exists a corresponding extended unsigned integer type with the same
amount of storage and alignment requirements. The standard and extended unsigned integer types are
collectively called unsigned integer types. The range of non-negative values of a signed integer type is a
subrange of the corresponding unsigned integer type, the representation of the same value in each of the two
types is the same, and the value representation of each corresponding signed/unsigned type shall be the same.
The standard signed integer types and standard unsigned integer types are collectively called the standard
integer types, and the extended signed integer types and extended unsigned integer types are collectively
called the extended integer types. The signed and unsigned integer types shall satisfy the constraints given in
the C standard, subclause 5.2.4.2.1.
4
Unsigned integers shall obey the laws of arithmetic modulo 2n where n is the number of bits in the value
representation of that particular size of integer.45
5
Type wchar_t is a distinct type whose values can represent distinct codes for all members of the largest
extended character set specified among the supported locales (25.3.1). Type wchar_t shall have the same
size, signedness, and alignment requirements (6.6.5) as one of the other integral types, called its underlying
type. Types char16_t and char32_t denote distinct types with the same size, signedness, and alignment as
uint_least16_t and uint_least32_t, respectively, in <cstdint>, called the underlying types.
6
Values of type bool are either true or false.46
[Note: There are no signed, unsigned, short, or long
bool types or values.
— end note ] Values of type bool participate in integral promotions (7.6).
7
Types bool, char, char16_t, char32_t, wchar_t, and the signed and unsigned integer types are collectively
called integral types.47 A synonym for integral type is integer type. The representations of integral types
shall define values by use of a pure binary numeration system.48 [Example: This document permits two’s
complement, ones’ complement and signed magnitude representations for integral types.
— end example ]
8
There are three floating-point types: float, double, and long double. The type double provides at least as
much precision as float, and the type long double provides at least as much precision as double. The set of
values of the type float is a subset of the set of values of the type double; the set of values of the type double
is a subset of the set of values of the type long double. The value representation of floating-point types is
implementation-defined. [Note: This document imposes no requirements on the accuracy of floating-point
operations; see also 21.3.
— end note ] Integral and floating types are collectively called arithmetic types.
Specializations of the standard library template std::numeric_limits (21.3) shall specify the maximum
and minimum values of each arithmetic type for an implementation.
9
A type cv void is an incomplete type that cannot be completed; such a type has an empty set of values. It is
used as the return type for functions that do not return a value. Any expression can be explicitly converted
to type cv void (8.5.3). An expression of type cv void shall be used only as an expression statement (9.2),
as an operand of a comma expression (8.5.19), as a second or third operand of ?: (8.5.16), as the operand
of typeid, noexcept, or decltype, as the expression in a return statement (9.6.3) for a function with the
return type cv void, or as the operand of an explicit conversion to type cv void.
10
A value of type std::nullptr_t is a null pointer constant (7.11). Such values participate in the pointer and
the pointer-to-member conversions (7.11, 7.12). sizeof(std::nullptr_t) shall be equal to sizeof(void*).
43) int must also be large enough to contain any value in the range [INT_MIN, INT_MAX], as defined in the header <climits>.
44) See 10.1.7.2 regarding the correspondence between types and the sequences of type-specifiers that designate them.
45) This implies that unsigned arithmetic does not overflow because a result that cannot be represented by the resulting
unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the
resulting unsigned integer type.
46) Using a bool value in ways described by this document as “undefined”, such as by examining the value of an uninitialized
automatic object, might cause it to behave as if it is neither true nor false.
47) Therefore, enumerations (10.2) are not integral; however, enumerations can be promoted to integral types as specified in 7.6.
48) A positional representation for integers that uses the binary digits 0 and 1, in which the values represented by successive
bits are additive, begin with 1, and are multiplied by successive integral power of 2, except perhaps for the bit with the highest
position. (Adapted from the American National Dictionary for Information Processing Systems.)
§ 6.7.1
60
11
[Note: Even if the implementation defines two or more basic types to have the same value representation,
they are nevertheless different types.
— end note ]
6.7.2
Compound types
[basic.compound]
1
Compound types can be constructed in the following ways:
(1.1)
—
arrays of objects of a given type, 11.3.4;
(1.2)
—
functions, which have parameters of given types and return void or references or objects of a given
type, 11.3.5;
(1.3)
—
pointers to cv void or objects or functions (including static members of classes) of a given type, 11.3.1;
(1.4)
—
references to objects or functions of a given type, 11.3.2. There are two types of references:
(1.4.1)
—
lvalue reference
(1.4.2)
—
rvalue reference
(1.5)
—
classes containing a sequence of objects of various types (Clause 12), a set of types, enumerations
and functions for manipulating these objects (12.2.1), and a set of restrictions on the access to these
entities (Clause 14);
(1.6)
—
unions, which are classes capable of containing objects of different types at different times, 12.3;
(1.7)
—
enumerations, which comprise a set of named constant values. Each distinct enumeration constitutes a
different enumerated type, 10.2;
(1.8)
—
pointers to non-static class members,49 which identify members of a given type within objects of a
given class, 11.3.3. Pointers to data members and pointers to member functions are collectively called
pointer-to-member types.
2
These methods of constructing types can be applied recursively; restrictions are mentioned in 11.3.1, 11.3.4,
11.3.5, and 11.3.2. Constructing a type such that the number of bytes in its object representation exceeds the
maximum value representable in the type std::size_t (21.2) is ill-formed.
3
The type of a pointer to cv void or a pointer to an object type is called an object pointer type. [Note: A
pointer to void does not have a pointer-to-object type, however, because void is not an object type.
— end
note ] The type of a pointer that can designate a function is called a function pointer type. A pointer to
objects of type T is referred to as a “pointer to T”. [ Example: A pointer to an object of type int is referred to
as “pointer to int” and a pointer to an object of class X is called a “pointer to X”. — end example ] Except
for pointers to static members, text referring to “pointers” does not apply to pointers to members. Pointers
to incomplete types are allowed although there are restrictions on what can be done with them (6.6.5). Every
value of pointer type is one of the following:
(3.1)
—
a pointer to an object or function (the pointer is said to point to the object or function), or
(3.2)
—
a pointer past the end of an object (8.5.6), or
(3.3)
—
the null pointer value (7.11) for that type, or
(3.4)
—
an invalid pointer value.
A value of a pointer type that is a pointer to or past the end of an object represents the address of the first
byte in memory (6.6.1) occupied by the object50 or the first byte in memory after the end of the storage
occupied by the object, respectively. [Note: A pointer past the end of an object (8.5.6) is not considered
to point to an unrelated object of the object’s type that might be located at that address. A pointer value
becomes invalid when the storage it denotes reaches the end of its storage duration; see 6.6.4.
— end note ]
For purposes of pointer arithmetic (8.5.6) and comparison (8.5.9, 8.5.10), a pointer past the end of the last
element of an array x of n elements is considered to be equivalent to a pointer to a hypothetical element x[n].
The value representation of pointer types is implementation-defined. Pointers to layout-compatible types
shall have the same value representation and alignment requirements (6.6.5). [ Note: Pointers to over-aligned
types (6.6.5) have no special representation, but their range of valid values is restricted by the extended
alignment requirement. — end note ]
4
Two objects a and b are pointer-interconvertible if:
(4.1)
—
they are the same object, or
49) Static class members are objects or functions, and pointers to them are ordinary pointers to objects or functions.
50) For an object that is not within its lifetime, this is the first byte in memory that it will occupy or used to occupy.
§ 6.7.2
61
(4.2)
—
one is a union object and the other is a non-static data member of that object (12.3), or
(4.3)
—
one is a standard-layout class object and the other is the first non-static data member of that object,
or, if the object has no non-static data members, the first base class subobject of that object (12.2), or
(4.4)
—
there exists an object c such that a and c are pointer-interconvertible, and c and b are pointer-
interconvertible.
If two objects are pointer-interconvertible, then they have the same address, and it is possible to obtain a
pointer to one from a pointer to the other via a reinterpret_cast (8.5.1.10). [ Note: An array object and
its first element are not pointer-interconvertible, even though they have the same address.
— end note ]
5
A pointer to cv-qualified (6.7.3) or cv-unqualified void can be used to point to objects of unknown type.
Such a pointer shall be able to hold any object pointer. An object of type cv void* shall have the same
representation and alignment requirements as cv char*.
6.7.3
CV-qualifiers
[basic.type.qualifier]
1
A type mentioned in 6.7.1 and 6.7.2 is a cv-unqualified type. Each type which is a cv-unqualified complete or
incomplete object type or is void (6.7) has three corresponding cv-qualified versions of its type: a const-
qualified version, a volatile-qualified version, and a const-volatile-qualified version. The type of an object (6.6.2)
includes the cv-qualifiers specified in the decl-specifier-seq (10.1), declarator (Clause 11), type-id (11.1), or
new-type-id (8.5.2.4) when the object is created.
(1.1)
—
A const object is an object of type const T or a non-mutable subobject of such an object.
(1.2)
—
A volatile object is an object of type volatile T, a subobject of such an object, or a mutable subobject
of a const volatile object.
(1.3)
—
A const volatile object is an object of type const volatile T, a non-mutable subobject of such an
object, a const subobject of a volatile object, or a non-mutable volatile subobject of a const object.
The cv-qualified or cv-unqualified versions of a type are distinct types; however, they shall have the same
representation and alignment requirements (6.6.5).51
2
A compound type (6.7.2) is not cv-qualified by the cv-qualifiers (if any) of the types from which it is
compounded. Any cv-qualifiers applied to an array type affect the array element type (11.3.4).
3
See 11.3.5 and 12.2.2.1 regarding function types that have cv-qualifier s.
4
There is a partial ordering on cv-qualifiers, so that a type can be said to be more cv-qualified than another.
Table 10 shows the relations that constitute this ordering.
Table 10 — Relations on const and volatile
no cv-qualifier
<
const
no cv-qualifier
<
volatile
no cv-qualifier
< const volatile
const
< const volatile
volatile
< const volatile
5
In this document, the notation cv (or cv1, cv2, etc.), used in the description of types, represents an arbitrary
set of cv-qualifiers, i.e., one of {const}, {volatile}, {const, volatile}, or the empty set. For a type cv T,
the top-level cv-qualifiers of that type are those denoted by cv. [ Example: The type corresponding to the
type-id const int& has no top-level cv-qualifiers. The type corresponding to the type-id volatile int *
const has the top-level cv-qualifier const. For a class type C, the type corresponding to the type-id void
(C::* volatile)(int) const has the top-level cv-qualifier volatile.
— end example ]
6
Cv-qualifiers applied to an array type attach to the underlying element type, so the notation “cv T”, where
T is an array type, refers to an array whose elements are so-qualified. An array type whose elements are
cv-qualified is also considered to have the same cv-qualifications as its elements. [ Example:
typedef char CA[5];
typedef const char CC;
CC arr1[5] = { 0 };
const CA arr2 = { 0 };
51) The same representation and alignment requirements are meant to imply interchangeability as arguments to functions,
return values from functions, and non-static data members of unions.
§ 6.7.3
62
The type of both arr1 and arr2 is “array of 5 const char”, and the array type is considered to be
const-qualified.
— end example ]
6.7.4
Integer conversion rank
[conv.rank]
1
Every integer type has an integer conversion rank defined as follows:
(1.1)
—
No two signed integer types other than char and signed char (if char is signed) shall have the same
rank, even if they have the same representation.
(1.2)
—
The rank of a signed integer type shall be greater than the rank of any signed integer type with a
smaller size.
(1.3)
—
The rank of long long int shall be greater than the rank of long int, which shall be greater than
the rank of int, which shall be greater than the rank of short int, which shall be greater than the
rank of signed char.
(1.4)
—
The rank of any unsigned integer type shall equal the rank of the corresponding signed integer type.
(1.5)
—
The rank of any standard integer type shall be greater than the rank of any extended integer type with
the same size.
(1.6)
—
The rank of char shall equal the rank of signed char and unsigned char.
(1.7)
—
The rank of bool shall be less than the rank of all other standard integer types.
(1.8)
—
The ranks of char16_t, char32_t, and wchar_t shall equal the ranks of their underlying types (6.7.1).
(1.9)
—
The rank of any extended signed integer type relative to another extended signed integer type with the
same size is implementation-defined, but still subject to the other rules for determining the integer
conversion rank.
(1.10)
—
For all integer types T1, T2, and T3, if T1 has greater rank than T2 and T2 has greater rank than T3,
then T1 shall have greater rank than T3.
[Note: The integer conversion rank is used in the definition of the integral promotions (7.6) and the usual
arithmetic conversions (8.2).
— end note ]
6.8
Program execution
[basic.exec]
6.8.1
Sequential execution
[intro.execution]
1
An instance of each object with automatic storage duration (6.6.4.3) is associated with each entry into its
block. Such an object exists and retains its last-stored value during the execution of the block and while the
block is suspended (by a call of a function or receipt of a signal).
2
A constituent expression is defined as follows:
(2.1)
—
The constituent expression of an expression is that expression.
(2.2)
—
The constituent expressions of a braced-init-list or of a (possibly parenthesized) expression-list are the
constituent expressions of the elements of the respective list.
(2.3)
—
The constituent expressions of a brace-or-equal-initializer of the form = initializer-clause are the
constituent expressions of the initializer-clause.
[ Example:
struct A { int x; };
struct B { int y; struct A a; };
B b = { 5, { 1+1 } };
The constituent expressions of the initializer used for the initialization of b are 5 and 1+1.
— end example ]
3
The immediate subexpressions of an expression e are
(3.1)
—
the constituent expressions of e’s operands (8.2),
(3.2)
—
any function call that e implicitly invokes,
(3.3)
—
if e is a lambda-expression (8.4.5), the initialization of the entities captured by copy and the constituent
expressions of the initializer of the init-captures,
(3.4)
—
if e is a function call (8.5.1.2) or implicitly invokes a function, the constituent expressions of each
default argument (11.3.6) used in the call, or
§ 6.8.1
63
(3.5)
—
if e creates an aggregate object (11.6.1), the constituent expressions of each default member initializer
(12.2) used in the initialization.
4
A subexpression of an expression e is an immediate subexpression of e or a subexpression of an immediate
subexpression of e. [ Note: Expressions appearing in the compound-statement of a lambda-expression are not
subexpressions of the lambda-expression.
— end note ]
5
A full-expression is
(5.1)
—
an unevaluated operand (8.2),
(5.2)
—
a constant-expression (8.6),
(5.3)
—
an init-declarator (Clause 11) or a mem-initializer (15.6.2), including the constituent expressions of the
initializer,
(5.4)
—
an invocation of a destructor generated at the end of the lifetime of an object other than a temporary
object (15.2), or
(5.5)
—
an expression that is not a subexpression of another expression and that is not otherwise part of a
full-expression.
If a language construct is defined to produce an implicit call of a function, a use of the language construct is
considered to be an expression for the purposes of this definition. Conversions applied to the result of an
expression in order to satisfy the requirements of the language construct in which the expression appears are
also considered to be part of the full-expression. For an initializer, performing the initialization of the entity
(including evaluating default member initializers of an aggregate) is also considered part of the full-expression.
[ Example:
struct S {
S(int i): I(i) { }
// full-expression is initialization of I
int& v() { return I; }
~S() noexcept(false) { }
private:
int I;
};
S s1(1);
// full-expression comprises call of S::S(int)
void f() {
S s2 = 2;
// full-expression comprises call of S::S(int)
if (S(3).v())
// full-expression includes lvalue-to-rvalue and int to bool conversions,
// performed before temporary is deleted at end of full-expression
{ }
bool b = noexcept(S());
// exception specification of destructor of S considered for noexcept
// full-expression is destruction of s2 at end of block
}
struct B {
B(S = S(0));
};
B b[2] = { B(), B() };
// full-expression is the entire initialization
// including the destruction of temporaries
— end example ]
6
[ Note: The evaluation of a full-expression can include the evaluation of subexpressions that are not lexically
part of the full-expression. For example, subexpressions involved in evaluating default arguments (11.3.6) are
considered to be created in the expression that calls the function, not the expression that defines the default
argument. — end note ]
7
Reading an object designated by a volatile glvalue (8.2.1), modifying an object, calling a library I/O
function, or calling a function that does any of those operations are all side effects, which are changes in the
state of the execution environment. Evaluation of an expression (or a subexpression) in general includes both
value computations (including determining the identity of an object for glvalue evaluation and fetching a
value previously assigned to an object for prvalue evaluation) and initiation of side effects. When a call to a
library I/O function returns or an access through a volatile glvalue is evaluated the side effect is considered
complete, even though some external actions implied by the call (such as the I/O itself) or by the volatile
access may not have completed yet.
§ 6.8.1
64
8
Sequenced before is an asymmetric, transitive, pair-wise relation between evaluations executed by a single
thread (6.8.2), which induces a partial order among those evaluations. Given any two evaluations A and B,
if A is sequenced before B (or, equivalently, B is sequenced after A), then the execution of A shall precede
the execution of B. If A is not sequenced before B and B is not sequenced before A, then A and B are
unsequenced.
[Note: The execution of unsequenced evaluations can overlap.
— end note ] Evaluations
A and B are indeterminately sequenced when either A is sequenced before B or B is sequenced before A,
but it is unspecified which. [Note: Indeterminately sequenced evaluations cannot overlap, but either could
be executed first.
— end note ] An expression X is said to be sequenced before an expression Y if every
value computation and every side effect associated with the expression X is sequenced before every value
computation and every side effect associated with the expression Y.
9
Every value computation and side effect associated with a full-expression is sequenced before every value
computation and side effect associated with the next full-expression to be evaluated.52
10
Except where noted, evaluations of operands of individual operators and of subexpressions of individual
expressions are unsequenced. [ Note: In an expression that is evaluated more than once during the execution
of a program, unsequenced and indeterminately sequenced evaluations of its subexpressions need not be
performed consistently in different evaluations.
— end note ] The value computations of the operands of
an operator are sequenced before the value computation of the result of the operator. If a side effect on a
memory location (6.6.1) is unsequenced relative to either another side effect on the same memory location or
a value computation using the value of any object in the same memory location, and they are not potentially
concurrent (6.8.2), the behavior is undefined. [ Note: The next subclause imposes similar, but more complex
restrictions on potentially concurrent computations.
— end note ]
[ Example:
void g(int i) {
i = 7, i++, i++;
// i becomes 9
i = i++ + 1;
// the value of i is incremented
i = i++ + i;
// the behavior is undefined
i = i + 1;
// the value of i is incremented
}
— end example ]
11
When calling a function (whether or not the function is inline), every value computation and side effect
associated with any argument expression, or with the postfix expression designating the called function, is
sequenced before execution of every expression or statement in the body of the called function. For each
function invocation F, for every evaluation A that occurs within F and every evaluation B that does not
occur within F but is evaluated on the same thread and as part of the same signal handler (if any), either A is
sequenced before B or B is sequenced before A.53 [ Note: If A and B would not otherwise be sequenced then
they are indeterminately sequenced.
— end note ] Several contexts in C++ cause evaluation of a function call,
even though no corresponding function call syntax appears in the translation unit. [ Example: Evaluation of
a new-expression invokes one or more allocation and constructor functions; see 8.5.2.4. For another example,
invocation of a conversion function (15.3.2) can arise in contexts in which no function call syntax appears.
— end example ] The sequencing constraints on the execution of the called function (as described above) are
features of the function calls as evaluated, whatever the syntax of the expression that calls the function might
be.
12
If a signal handler is executed as a result of a call to the std::raise function, then the execution of the
handler is sequenced after the invocation of the std::raise function and before its return. [ Note: When a
signal is received for another reason, the execution of the signal handler is usually unsequenced with respect
to the rest of the program.
— end note ]
6.8.2
Multi-threaded executions and data races
[intro.multithread]
1
A thread of execution (also known as a thread) is a single flow of control within a program, including the initial
invocation of a specific top-level function, and recursively including every function invocation subsequently
executed by the thread. [ Note: When one thread creates another, the initial call to the top-level function of
the new thread is executed by the new thread, not by the creating thread.
— end note ] Every thread in a
52) As specified in 15.2, after a full-expression is evaluated, a sequence of zero or more invocations of destructor functions for
temporary objects takes place, usually in reverse order of the construction of each temporary object.
53) In other words, function executions do not interleave with each other.
§ 6.8.2
65
program can potentially access every object and function in a program.54 Under a hosted implementation, a
C++ program can have more than one thread running concurrently. The execution of each thread proceeds as
defined by the remainder of this document. The execution of the entire program consists of an execution of
all of its threads. [ Note: Usually the execution can be viewed as an interleaving of all its threads. However,
some kinds of atomic operations, for example, allow executions inconsistent with a simple interleaving, as
described below.
— end note ] Under a freestanding implementation, it is implementation-defined whether a
program can have more than one thread of execution.
2
For a signal handler that is not executed as a result of a call to the std::raise function, it is unspecified
which thread of execution contains the signal handler invocation.
6.8.2.1
Data races
[intro.races]
1
The value of an object visible to a thread T at a particular point is the initial value of the object, a value
assigned to the object by T, or a value assigned to the object by another thread, according to the rules below.
[Note: In some cases, there may instead be undefined behavior. Much of this subclause is motivated by
the desire to support atomic operations with explicit and detailed visibility constraints. However, it also
implicitly supports a simpler view for more restricted programs.
— end note ]
2
Two expression evaluations conflict if one of them modifies a memory location (6.6.1) and the other one reads
or modifies the same memory location.
3
The library defines a number of atomic operations (Clause 32) and operations on mutexes (Clause 33) that are
specially identified as synchronization operations. These operations play a special role in making assignments
in one thread visible to another. A synchronization operation on one or more memory locations is either a
consume operation, an acquire operation, a release operation, or both an acquire and release operation. A
synchronization operation without an associated memory location is a fence and can be either an acquire
fence, a release fence, or both an acquire and release fence. In addition, there are relaxed atomic operations,
which are not synchronization operations, and atomic read-modify-write operations, which have special
characteristics.
[Note: For example, a call that acquires a mutex will perform an acquire operation on
the locations comprising the mutex. Correspondingly, a call that releases the same mutex will perform a
release operation on those same locations. Informally, performing a release operation on A forces prior side
effects on other memory locations to become visible to other threads that later perform a consume or an
acquire operation on A. “Relaxed” atomic operations are not synchronization operations even though, like
synchronization operations, they cannot contribute to data races.
— end note ]
4
All modifications to a particular atomic object M occur in some particular total order, called the modification
order of M. [ Note: There is a separate order for each atomic object. There is no requirement that these can
be combined into a single total order for all objects. In general this will be impossible since different threads
may observe modifications to different objects in inconsistent orders.
— end note ]
5
A release sequence headed by a release operation A on an atomic object M is a maximal contiguous sub-
sequence of side effects in the modification order of M, where the first operation is A, and every subsequent
operation
(5.1)
—
is performed by the same thread that performed A, or
(5.2)
—
is an atomic read-modify-write operation.
6
Certain library calls synchronize with other library calls performed by another thread. For example, an
atomic store-release synchronizes with a load-acquire that takes its value from the store (32.4). [ Note: Except
in the specified cases, reading a later value does not necessarily ensure visibility as described below. Such a
requirement would sometimes interfere with efficient implementation.
— end note ] [ Note: The specifications
of the synchronization operations define when one reads the value written by another. For atomic objects,
the definition is clear. All operations on a given mutex occur in a single total order. Each mutex acquisition
“reads the value written” by the last mutex release.
— end note ]
7
An evaluation A carries a dependency to an evaluation B if
(7.1)
—
the value of A is used as an operand of B, unless:
(7.1.1)
—
B is an invocation of any specialization of std::kill_dependency (32.4), or
(7.1.2)
—
A is the left operand of a built-in logical AND (&&, see 8.5.14) or logical OR (||, see 8.5.15)
operator, or
54) An object with automatic or thread storage duration (6.6.4) is associated with one specific thread, and can be accessed by
a different thread only indirectly through a pointer or reference (6.7.2).
§ 6.8.2.1
66
(7.1.3)
—
A is the left operand of a conditional (?:, see 8.5.16) operator, or
(7.1.4)
—
A is the left operand of the built-in comma (,) operator (8.5.19);
or
(7.2)
—
A writes a scalar object or bit-field M, B reads the value written by A from M, and A is sequenced
before B, or
(7.3)
—
for some evaluation X, A carries a dependency to X, and X carries a dependency to B.
[ Note: “Carries a dependency to” is a subset of “is sequenced before”, and is similarly strictly intra-thread.
— end note ]
8
An evaluation A is dependency-ordered before an evaluation B if
(8.1)
—
A performs a release operation on an atomic object M, and, in another thread, B performs a consume
operation on M and reads a value written by any side effect in the release sequence headed by A, or
(8.2)
—
for some evaluation X, A is dependency-ordered before X and X carries a dependency to B.
[Note: The relation “is dependency-ordered before” is analogous to “synchronizes with”, but uses release/-
consume in place of release/acquire.
— end note ]
9
An evaluation A inter-thread happens before an evaluation B if
(9.1)
—
A synchronizes with B, or
(9.2)
—
A is dependency-ordered before B, or
(9.3)
—
for some evaluation X
(9.3.1)
—
A synchronizes with X and X is sequenced before B, or
(9.3.2)
—
A is sequenced before X and X inter-thread happens before B, or
(9.3.3)
—
A inter-thread happens before X and X inter-thread happens before B.
[ Note: The “inter-thread happens before” relation describes arbitrary concatenations of “sequenced before”,
“synchronizes with” and “dependency-ordered before” relationships, with two exceptions. The first exception
is that a concatenation is not permitted to end with “dependency-ordered before” followed by “sequenced
before”. The reason for this limitation is that a consume operation participating in a “dependency-ordered
before” relationship provides ordering only with respect to operations to which this consume operation
actually carries a dependency. The reason that this limitation applies only to the end of such a concatenation
is that any subsequent release operation will provide the required ordering for a prior consume operation.
The second exception is that a concatenation is not permitted to consist entirely of “sequenced before”. The
reasons for this limitation are (1) to permit “inter-thread happens before” to be transitively closed and (2)
the “happens before” relation, defined below, provides for relationships consisting entirely of “sequenced
before”.
— end note ]
10
An evaluation A happens before an evaluation B (or, equivalently, B happens after A) if:
(10.1)
—
A is sequenced before B, or
(10.2)
—
A inter-thread happens before B.
The implementation shall ensure that no program execution demonstrates a cycle in the “happens before”
relation. [ Note: This cycle would otherwise be possible only through the use of consume operations.
— end
note ]
11
An evaluation A strongly happens before an evaluation B if either
(11.1)
—
A is sequenced before B, or
(11.2)
—
A synchronizes with B, or
(11.3)
—
A strongly happens before X and X strongly happens before B.
[ Note: In the absence of consume operations, the happens before and strongly happens before relations are
identical. Strongly happens before essentially excludes consume operations.
— end note ]
12
A visible side effect A on a scalar object or bit-field M with respect to a value computation B of M satisfies
the conditions:
(12.1)
—
A happens before B and
(12.2)
—
there is no other side effect X to M such that A happens before X and X happens before B.
§ 6.8.2.1
67
The value of a non-atomic scalar object or bit-field M, as determined by evaluation B, shall be the value
stored by the visible side effect A. [ Note: If there is ambiguity about which side effect to a non-atomic object
or bit-field is visible, then the behavior is either unspecified or undefined.
— end note ] [ Note: This states
that operations on ordinary objects are not visibly reordered. This is not actually detectable without data
races, but it is necessary to ensure that data races, as defined below, and with suitable restrictions on the use
of atomics, correspond to data races in a simple interleaved (sequentially consistent) execution.
— end note ]
13
The value of an atomic object M, as determined by evaluation B, shall be the value stored by some side effect
A that modifies M, where B does not happen before A. [ Note: The set of such side effects is also restricted
by the rest of the rules described here, and in particular, by the coherence requirements below.
— end note ]
14
If an operation A that modifies an atomic object M happens before an operation B that modifies M, then
A shall be earlier than B in the modification order of M. [Note: This requirement is known as write-write
coherence.
— end note ]
15
If a value computation A of an atomic object M happens before a value computation B of M, and A takes
its value from a side effect X on M, then the value computed by B shall either be the value stored by X or
the value stored by a side effect Y on M, where Y follows X in the modification order of M. [ Note: This
requirement is known as read-read coherence.
— end note ]
16
If a value computation A of an atomic object M happens before an operation B that modifies M, then A
shall take its value from a side effect X on M, where X precedes B in the modification order of M. [Note:
This requirement is known as read-write coherence.
— end note ]
17
If a side effect X on an atomic object M happens before a value computation B of M, then the evaluation B
shall take its value from X or from a side effect Y that follows X in the modification order of M. [ Note: This
requirement is known as write-read coherence.
— end note ]
18
[ Note: The four preceding coherence requirements effectively disallow compiler reordering of atomic operations
to a single object, even if both operations are relaxed loads. This effectively makes the cache coherence
guarantee provided by most hardware available to C++ atomic operations.
— end note ]
19
[ Note: The value observed by a load of an atomic depends on the “happens before” relation, which depends
on the values observed by loads of atomics. The intended reading is that there must exist an association of
atomic loads with modifications they observe that, together with suitably chosen modification orders and
the “happens before” relation derived as described above, satisfy the resulting constraints as imposed here.
— end note ]
20
Two actions are potentially concurrent if
(20.1)
—
they are performed by different threads, or
(20.2)
—
they are unsequenced, at least one is performed by a signal handler, and they are not both performed
by the same signal handler invocation.
The execution of a program contains a data race if it contains two potentially concurrent conflicting actions,
at least one of which is not atomic, and neither happens before the other, except for the special case for
signal handlers described below. Any such data race results in undefined behavior. [ Note: It can be shown
that programs that correctly use mutexes and memory_order::seq_cst operations to prevent all data races
and use no other synchronization operations behave as if the operations executed by their constituent threads
were simply interleaved, with each value computation of an object being taken from the last side effect on that
object in that interleaving. This is normally referred to as “sequential consistency”. However, this applies only
to data-race-free programs, and data-race-free programs cannot observe most program transformations that
do not change single-threaded program semantics. In fact, most single-threaded program transformations
continue to be allowed, since any program that behaves differently as a result must perform an undefined
operation.
— end note ]
21
Two accesses to the same object of type volatile std::sig_atomic_t do not result in a data race if
both occur in the same thread, even if one or more occurs in a signal handler. For each signal handler
invocation, evaluations performed by the thread invoking a signal handler can be divided into two groups A
and B, such that no evaluations in B happen before evaluations in A, and the evaluations of such volatile
std::sig_atomic_t objects take values as though all evaluations in A happened before the execution of the
signal handler and the execution of the signal handler happened before all evaluations in B.
22
[Note: Compiler transformations that introduce assignments to a potentially shared memory location that
would not be modified by the abstract machine are generally precluded by this document, since such an
assignment might overwrite another assignment by a different thread in cases in which an abstract machine
§ 6.8.2.1
68
execution would not have encountered a data race. This includes implementations of data member assignment
that overwrite adjacent members in separate memory locations. Reordering of atomic loads in cases in which
the atomics in question may alias is also generally precluded, since this may violate the coherence rules.
— end note ]
23
[ Note: Transformations that introduce a speculative read of a potentially shared memory location may not
preserve the semantics of the C++ program as defined in this document, since they potentially introduce a
data race. However, they are typically valid in the context of an optimizing compiler that targets a specific
machine with well-defined semantics for data races. They would be invalid for a hypothetical machine that is
not tolerant of races or provides hardware race detection.
— end note ]
6.8.2.2
Forward progress
[intro.progress]
1
The implementation may assume that any thread will eventually do one of the following:
(1.1)
—
terminate,
(1.2)
—
make a call to a library I/O function,
(1.3)
—
perform an access through a volatile glvalue, or
(1.4)
—
perform a synchronization operation or an atomic operation.
[Note: This is intended to allow compiler transformations such as removal of empty loops, even when
termination cannot be proven.
— end note ]
2
Executions of atomic functions that are either defined to be lock-free (32.8) or indicated as lock-free (32.5)
are lock-free executions.
(2.1)
—
If there is only one thread that is not blocked (3.6) in a standard library function, a lock-free execution in
that thread shall complete. [ Note: Concurrently executing threads may prevent progress of a lock-free
execution. For example, this situation can occur with load-locked store-conditional implementations.
This property is sometimes termed obstruction-free.
— end note ]
(2.2)
—
When one or more lock-free executions run concurrently, at least one should complete.
[Note: It
is difficult for some implementations to provide absolute guarantees to this effect, since repeated
and particularly inopportune interference from other threads may prevent forward progress, e.g., by
repeatedly stealing a cache line for unrelated purposes between load-locked and store-conditional
instructions. Implementations should ensure that such effects cannot indefinitely delay progress under
expected operating conditions, and that such anomalies can therefore safely be ignored by programmers.
Outside this document, this property is sometimes termed lock-free.
— end note ]
3
During the execution of a thread of execution, each of the following is termed an execution step:
(3.1)
—
termination of the thread of execution,
(3.2)
—
performing an access through a volatile glvalue, or
(3.3)
—
completion of a call to a library I/O function, a synchronization operation, or an atomic operation.
4
An invocation of a standard library function that blocks (3.6) is considered to continuously execute execution
steps while waiting for the condition that it blocks on to be satisfied. [ Example: A library I/O function that
blocks until the I/O operation is complete can be considered to continuously check whether the operation
is complete. Each such check might consist of one or more execution steps, for example using observable
behavior of the abstract machine.
— end example ]
5
[ Note: Because of this and the preceding requirement regarding what threads of execution have to perform
eventually, it follows that no thread of execution can execute forever without an execution step occurring.
— end note ]
6
A thread of execution makes progress when an execution step occurs or a lock-free execution does not complete
because there are other concurrent threads that are not blocked in a standard library function (see above).
7
For a thread of execution providing concurrent forward progress guarantees, the implementation ensures
that the thread will eventually make progress for as long as it has not terminated. [Note: This is required
regardless of whether or not other threads of executions (if any) have been or are making progress. To
eventually fulfill this requirement means that this will happen in an unspecified but finite amount of time.
— end note ]
§ 6.8.2.2
69
8
It is implementation-defined whether the implementation-created thread of execution that executes main
(6.8.3.1) and the threads of execution created by std::thread (33.3.2) provide concurrent forward progress
guarantees. [ Note: General-purpose implementations should provide these guarantees.
— end note ]
9
For a thread of execution providing parallel forward progress guarantees, the implementation is not required
to ensure that the thread will eventually make progress if it has not yet executed any execution step; once
this thread has executed a step, it provides concurrent forward progress guarantees.
10
[ Note: This does not specify a requirement for when to start this thread of execution, which will typically be
specified by the entity that creates this thread of execution. For example, a thread of execution that provides
concurrent forward progress guarantees and executes tasks from a set of tasks in an arbitrary order, one after
the other, satisfies the requirements of parallel forward progress for these tasks.
— end note ]
11
For a thread of execution providing weakly parallel forward progress guarantees, the implementation does not
ensure that the thread will eventually make progress.
12
[Note: Threads of execution providing weakly parallel forward progress guarantees cannot be expected to
make progress regardless of whether other threads make progress or not; however, blocking with forward
progress guarantee delegation, as defined below, can be used to ensure that such threads of execution make
progress eventually.
— end note ]
13
Concurrent forward progress guarantees are stronger than parallel forward progress guarantees, which in
turn are stronger than weakly parallel forward progress guarantees.
[Note: For example, some kinds of
synchronization between threads of execution may only make progress if the respective threads of execution
provide parallel forward progress guarantees, but will fail to make progress under weakly parallel guarantees.
— end note ]
14
When a thread of execution P is specified to block with forward progress guarantee delegation on the completion
of a set S of threads of execution, then throughout the whole time of P being blocked on S, the implementation
shall ensure that the forward progress guarantees provided by at least one thread of execution in S is at least
as strong as P’s forward progress guarantees. [ Note: It is unspecified which thread or threads of execution
in S are chosen and for which number of execution steps. The strengthening is not permanent and not
necessarily in place for the rest of the lifetime of the affected thread of execution. As long as P is blocked,
the implementation has to eventually select and potentially strengthen a thread of execution in S. — end
note ] Once a thread of execution in S terminates, it is removed from S. Once S is empty, P is unblocked.
15
[Note: A thread of execution B thus can temporarily provide an effectively stronger forward progress
guarantee for a certain amount of time, due to a second thread of execution A being blocked on it with
forward progress guarantee delegation. In turn, if B then blocks with forward progress guarantee delegation
on C, this may also temporarily provide a stronger forward progress guarantee to C. — end note ]
16
[Note: If all threads of execution in S finish executing (e.g., they terminate and do not use blocking
synchronization incorrectly), then P’s execution of the operation that blocks with forward progress guarantee
delegation will not result in P’s progress guarantee being effectively weakened.
— end note ]
17
[Note: This does not remove any constraints regarding blocking synchronization for threads of execution
providing parallel or weakly parallel forward progress guarantees because the implementation is not required
to strengthen a particular thread of execution whose too-weak progress guarantee is preventing overall
progress.
— end note ]
18
An implementation should ensure that the last value (in modification order) assigned by an atomic or
synchronization operation will become visible to all other threads in a finite period of time.
6.8.3
Start and termination
[basic.start]
6.8.3.1
main function
[basic.start.main]
1
A program shall contain a global function called main. Executing a program starts a main thread of
execution (6.8.2, 33.3) in which the main function is invoked, and in which variables of static storage duration
might be initialized (6.8.3.2) and destroyed (6.8.3.4). It is implementation-defined whether a program in
a freestanding environment is required to define a main function. [Note: In a freestanding environment,
start-up and termination is implementation-defined; start-up contains the execution of constructors for objects
of namespace scope with static storage duration; termination contains the execution of destructors for objects
with static storage duration.
— end note ]
§ 6.8.3.1
70
2
An implementation shall not predefine the main function. This function shall not be overloaded. Its type
shall have C++ language linkage and it shall have a declared return type of type int, but otherwise its type
is implementation-defined. An implementation shall allow both
(2.1)
—
a function of () returning int and
(2.2)
—
a function of (int, pointer to pointer to char) returning int
as the type of main (11.3.5). In the latter form, for purposes of exposition, the first function parameter is
called argc and the second function parameter is called argv, where argc shall be the number of arguments
passed to the program from the environment in which the program is run. If argc is nonzero these arguments
shall be supplied in argv[0] through argv[argc-1] as pointers to the initial characters of null-terminated
multibyte strings (ntmbss) (20.4.2.1.5.2) and argv[0] shall be the pointer to the initial character of a ntmbs
that represents the name used to invoke the program or "". The value of argc shall be non-negative. The
value of argv[argc] shall be 0. [ Note: It is recommended that any further (optional) parameters be added
after argv.
— end note ]
3
The function main shall not be used within a program. The linkage (6.5) of main is implementation-defined. A
program that defines main as deleted or that declares main to be inline, static, or constexpr is ill-formed.
The main function shall not be declared with a linkage-specification (10.5). A program that declares a variable
main at global scope or that declares the name main with C language linkage (in any namespace) is ill-formed.
The name main is not otherwise reserved. [Example: Member functions, classes, and enumerations can be
called main, as can entities in other namespaces.
— end example ]
4
Terminating the program without leaving the current block (e.g., by calling the function std::exit(int)
(21.5)) does not destroy any objects with automatic storage duration (15.4). If std::exit is called to end a
program during the destruction of an object with static or thread storage duration, the program has undefined
behavior.
5
A return statement in main has the effect of leaving the main function (destroying any objects with automatic
storage duration) and calling std::exit with the return value as the argument. If control flows off the end
of the compound-statement of main, the effect is equivalent to a return with operand 0 (see also 18.3).
6.8.3.2
Static initialization
[basic.start.static]
1
Variables with static storage duration are initialized as a consequence of program initiation. Variables with
thread storage duration are initialized as a consequence of thread execution. Within each of these phases of
initiation, initialization occurs as follows.
2
A constant initializer for a variable or temporary object o is an initializer whose full-expression is a constant
expression, except that if o is an object, such an initializer may also invoke constexpr constructors for o and
its subobjects even if those objects are of non-literal class types. [ Note: Such a class may have a non-trivial
destructor.
— end note ] Constant initialization is performed if a variable or temporary object with static
or thread storage duration is initialized by a constant initializer for the entity. If constant initialization
is not performed, a variable with static storage duration (6.6.4.1) or thread storage duration (6.6.4.2) is
zero-initialized (11.6). Together, zero-initialization and constant initialization are called static initialization;
all other initialization is dynamic initialization. All static initialization strongly happens before (6.8.2.1) any
dynamic initialization. [ Note: The dynamic initialization of non-local variables is described in 6.8.3.3; that
of local static variables is described in 9.7.
— end note ]
3
An implementation is permitted to perform the initialization of a variable with static or thread storage
duration as a static initialization even if such initialization is not required to be done statically, provided that
(3.1)
—
the dynamic version of the initialization does not change the value of any other object of static or
thread storage duration prior to its initialization, and
(3.2)
—
the static version of the initialization produces the same value in the initialized variable as would be
produced by the dynamic initialization if all variables not required to be initialized statically were
initialized dynamically.
[ Note: As a consequence, if the initialization of an object obj1 refers to an object obj2 of namespace scope
potentially requiring dynamic initialization and defined later in the same translation unit, it is unspecified
whether the value of obj2 used will be the value of the fully initialized obj2 (because obj2 was statically
initialized) or will be the value of obj2 merely zero-initialized. For example,
inline double fd() { return 1.0; }
extern double d1;
§ 6.8.3.2
71
double d2 = d1;
// unspecified:
// may be statically initialized to 0.0 or
// dynamically initialized to 0.0 if d1 is
// dynamically initialized, or 1.0 otherwise
double d1 = fd();
// may be initialized statically or dynamically to 1.0
— end note ]
6.8.3.3
Dynamic initialization of non-local variables
[basic.start.dynamic]
1
Dynamic initialization of a non-local variable with static storage duration is unordered if the variable is an
implicitly or explicitly instantiated specialization, is partially-ordered if the variable is an inline variable that
is not an implicitly or explicitly instantiated specialization, and otherwise is ordered. [Note: An explicitly
specialized non-inline static data member or variable template specialization has ordered initialization. — end
note ]
2
Dynamic initialization of non-local variables V and W with static storage duration are ordered as follows:
(2.1)
—
If V and W have ordered initialization and V is defined before W within a single translation unit, the
initialization of V is sequenced before the initialization of W.
(2.2)
—
If V has partially-ordered initialization, W does not have unordered initialization, and V is defined before
W in every translation unit in which W is defined, then
(2.2.1)
—
if the program starts a thread (6.8.2) other than the main thread (6.8.3.1), the initialization of V
strongly happens before the initialization of W;
(2.2.2)
—
otherwise, the initialization of V is sequenced before the initialization of W.
(2.3)
—
Otherwise, if the program starts a thread other than the main thread before either V or W is initialized,
it is unspecified in which threads the initializations of V and W occur; the initializations are unsequenced
if they occur in the same thread.
(2.4)
—
Otherwise, the initializations of V and W are indeterminately sequenced.
[Note: This definition permits initialization of a sequence of ordered variables concurrently with another
sequence.
— end note ]
3
A non-initialization odr-use is an odr-use (6.2) not caused directly or indirectly by the initialization of a
non-local static or thread storage duration variable.
4
It is implementation-defined whether the dynamic initialization of a non-local non-inline variable with static
storage duration is sequenced before the first statement of main or is deferred. If it is deferred, it strongly
happens before any non-initialization odr-use of any non-inline function or non-inline variable defined in the
same translation unit as the variable to be initialized.55 It is implementation-defined in which threads and
at which points in the program such deferred dynamic initialization occurs. [Note: Such points should be
chosen in a way that allows the programmer to avoid deadlocks.
— end note ] [ Example:
// - File 1 -
#include "a.h"
#include "b.h"
B b;
A::A(){
b.Use();
}
// - File 2 -
#include "a.h"
A a;
// - File 3 -
#include "a.h"
#include "b.h"
extern A a;
extern B b;
55) A non-local variable with static storage duration having initialization with side effects is initialized in this case, even if it is
not itself odr-used (6.2, 6.6.4.1).
§ 6.8.3.3
72
int main() {
a.Use();
b.Use();
}
It is implementation-defined whether either a or b is initialized before main is entered or whether the
initializations are delayed until a is first odr-used in main. In particular, if a is initialized before main is
entered, it is not guaranteed that b will be initialized before it is odr-used by the initialization of a, that is,
before A::A is called. If, however, a is initialized at some point after the first statement of main, b will be
initialized prior to its use in A::A. — end example ]
5
It is implementation-defined whether the dynamic initialization of a non-local inline variable with static
storage duration is sequenced before the first statement of main or is deferred. If it is deferred, it strongly
happens before any non-initialization odr-use of that variable. It is implementation-defined in which threads
and at which points in the program such deferred dynamic initialization occurs.
6
It is implementation-defined whether the dynamic initialization of a non-local non-inline variable with thread
storage duration is sequenced before the first statement of the initial function of a thread or is deferred. If it is
deferred, the initialization associated with the entity for thread t is sequenced before the first non-initialization
odr-use by t of any non-inline variable with thread storage duration defined in the same translation unit
as the variable to be initialized. It is implementation-defined in which threads and at which points in the
program such deferred dynamic initialization occurs.
7
If the initialization of a non-local variable with static or thread storage duration exits via an exception,
std::terminate is called (18.5.1).
6.8.3.4
Termination
[basic.start.term]
1
Destructors (15.4) for initialized objects (that is, objects whose lifetime (6.6.3) has begun) with static storage
duration, and functions registered with std::atexit, are called as part of a call to std::exit (21.5). The
call to std::exit is sequenced before the invocations of the destructors and the registered functions. [ Note:
Returning from main invokes std::exit (6.8.3.1).
— end note ]
2
Destructors for initialized objects with thread storage duration within a given thread are called as a result
of returning from the initial function of that thread and as a result of that thread calling std::exit. The
completions of the destructors for all initialized objects with thread storage duration within that thread
strongly happen before the initiation of the destructors of any object with static storage duration.
3
If the completion of the constructor or dynamic initialization of an object with static storage duration
strongly happens before that of another, the completion of the destructor of the second is sequenced before
the initiation of the destructor of the first. If the completion of the constructor or dynamic initialization of an
object with thread storage duration is sequenced before that of another, the completion of the destructor of
the second is sequenced before the initiation of the destructor of the first. If an object is initialized statically,
the object is destroyed in the same order as if the object was dynamically initialized. For an object of array
or class type, all subobjects of that object are destroyed before any block-scope object with static storage
duration initialized during the construction of the subobjects is destroyed. If the destruction of an object
with static or thread storage duration exits via an exception, std::terminate is called (18.5.1).
4
If a function contains a block-scope object of static or thread storage duration that has been destroyed and the
function is called during the destruction of an object with static or thread storage duration, the program has
undefined behavior if the flow of control passes through the definition of the previously destroyed block-scope
object. Likewise, the behavior is undefined if the block-scope object is used indirectly (i.e., through a pointer)
after its destruction.
5
If the completion of the initialization of an object with static storage duration strongly happens before a call
to std::atexit (see <cstdlib>, 21.5), the call to the function passed to std::atexit is sequenced before
the call to the destructor for the object. If a call to std::atexit strongly happens before the completion of
the initialization of an object with static storage duration, the call to the destructor for the object is sequenced
before the call to the function passed to std::atexit. If a call to std::atexit strongly happens before
another call to std::atexit, the call to the function passed to the second std::atexit call is sequenced
before the call to the function passed to the first std::atexit call.
6
If there is a use of a standard library object or function not permitted within signal handlers (21.11) that
does not happen before (6.8.2) completion of destruction of objects with static storage duration and execution
of std::atexit registered functions (21.5), the program has undefined behavior. [ Note: If there is a use of
an object with static storage duration that does not happen before the object’s destruction, the program
§ 6.8.3.4
73
has undefined behavior. Terminating every thread before a call to std::exit or the exit from main is
sufficient, but not necessary, to satisfy these requirements. These requirements permit thread managers as
static-storage-duration objects.
— end note ]
7
Calling the function std::abort() declared in <cstdlib> terminates the program without executing any
destructors and without calling the functions passed to std::atexit() or std::at_quick_exit().
§ 6.8.3.4
74
7
Standard conversions
[conv]
1
Standard conversions are implicit conversions with built-in meaning. Clause 7 enumerates the full set of such
conversions. A standard conversion sequence is a sequence of standard conversions in the following order:
(1.1)
—
Zero or one conversion from the following set: lvalue-to-rvalue conversion, array-to-pointer conversion,
and function-to-pointer conversion.
(1.2)
—
Zero or one conversion from the following set: integral promotions, floating-point promotion, integral
conversions, floating-point conversions, floating-integral conversions, pointer conversions, pointer-to-
member conversions, and boolean conversions.
(1.3)
—
Zero or one function pointer conversion.
(1.4)
—
Zero or one qualification conversion.
[Note: A standard conversion sequence can be empty, i.e., it can consist of no conversions.
— end note ]
A standard conversion sequence will be applied to an expression if necessary to convert it to a required
destination type.
2
[ Note: Expressions with a given type will be implicitly converted to other types in several contexts:
(2.1)
—
When used as operands of operators. The operator’s requirements for its operands dictate the destination
type (8.5).
(2.2)
—
When used in the condition of an if statement or iteration statement (9.4, 9.5). The destination type
is bool.
(2.3)
—
When used in the expression of a switch statement. The destination type is integral (9.4).
(2.4)
—
When used as the source expression for an initialization (which includes use as an argument in a
function call and use as the expression in a return statement). The type of the entity being initialized
is (generally) the destination type. See 11.6, 11.6.3.
— end note ]
3
An expression e can be implicitly converted to a type T if and only if the declaration T t=e; is well-formed,
for some invented temporary variable t (11.6).
4
Certain language constructs require that an expression be converted to a Boolean value. An expression e
appearing in such a context is said to be contextually converted to bool and is well-formed if and only if the
declaration bool t(e); is well-formed, for some invented temporary variable t (11.6).
5
Certain language constructs require conversion to a value having one of a specified set of types appropriate to
the construct. An expression e of class type E appearing in such a context is said to be contextually implicitly
converted to a specified type T and is well-formed if and only if e can be implicitly converted to a type T
that is determined as follows: E is searched for non-explicit conversion functions whose return type is cv T or
reference to cv T such that T is allowed by the context. There shall be exactly one such T.
6
The effect of any implicit conversion is the same as performing the corresponding declaration and initialization
and then using the temporary variable as the result of the conversion. The result is an lvalue if T is an lvalue
reference type or an rvalue reference to function type (11.3.2), an xvalue if T is an rvalue reference to object
type, and a prvalue otherwise. The expression e is used as a glvalue if and only if the initialization uses it as
a glvalue.
7
[Note: For class types, user-defined conversions are considered as well; see 15.3. In general, an implicit
conversion sequence (16.3.3.1) consists of a standard conversion sequence followed by a user-defined conversion
followed by another standard conversion sequence.
— end note ]
8
[ Note: There are some contexts where certain conversions are suppressed. For example, the lvalue-to-rvalue
conversion is not done on the operand of the unary & operator. Specific exceptions are given in the descriptions
of those operators and contexts.
— end note ]
Standard conversions
75
7.1
Lvalue-to-rvalue conversion
[conv.lval]
1
A glvalue (8.2.1) of a non-function, non-array type T can be converted to a prvalue.56 If T is an incomplete
type, a program that necessitates this conversion is ill-formed. If T is a non-class type, the type of the prvalue
is the cv-unqualified version of T. Otherwise, the type of the prvalue is T.57
2
When an lvalue-to-rvalue conversion is applied to an expression e, and either
(2.1)
—
e is not potentially evaluated, or
(2.2)
—
the evaluation of e results in the evaluation of a member ex of the set of potential results of e, and ex
names a variable x that is not odr-used by ex (6.2),
the value contained in the referenced object is not accessed. [ Example:
struct S { int n; };
auto f() {
S x { 1 };
constexpr S y { 2 };
return [&](bool b) { return (b ? y : x).n; };
}
auto g = f();
int m = g(false);
// undefined behavior due to access of x.n outside its lifetime
int n = g(true);
// OK, does not access y.n
— end example ]
3
The result of the conversion is determined according to the following rules:
(3.1)
—
If T is cv std::nullptr_t, the result is a null pointer constant (7.11). [ Note: Since no value is fetched
from memory, there is no side effect for a volatile access (6.8.1), and an inactive member of a union (12.3)
may be accessed. — end note ]
(3.2)
—
Otherwise, if T has a class type, the conversion copy-initializes the result object from the glvalue.
(3.3)
—
Otherwise, if the object to which the glvalue refers contains an invalid pointer value (6.6.4.4.2, 6.6.4.4.3),
the behavior is implementation-defined.
(3.4)
—
Otherwise, the value contained in the object indicated by the glvalue is the prvalue result.
4
[ Note: See also 8.2.1. — end note ]
7.2
Array-to-pointer conversion
[conv.array]
1
An lvalue or rvalue of type “array of N T” or “array of unknown bound of T” can be converted to a prvalue of
type “pointer to T”. The temporary materialization conversion (7.4) is applied. The result is a pointer to the
first element of the array.
7.3
Function-to-pointer conversion
[conv.func]
1
An lvalue of function type T can be converted to a prvalue of type “pointer to T”. The result is a pointer to
the function.58
2
[ Note: See 16.4 for additional rules for the case where the function is overloaded.
— end note ]
7.4
Temporary materialization conversion
[conv.rval]
1
A prvalue of type T can be converted to an xvalue of type T. This conversion initializes a temporary
object (15.2) of type T from the prvalue by evaluating the prvalue with the temporary object as its result
object, and produces an xvalue denoting the temporary object. T shall be a complete type. [ Note: If T is a
class type (or array thereof), it must have an accessible and non-deleted destructor; see 15.4.
— end note ]
[ Example:
struct X { int n; };
int k = X().n;
// OK, X() prvalue is converted to xvalue
— end example ]
56) For historical reasons, this conversion is called the “lvalue-to-rvalue” conversion, even though that name does not accurately
reflect the taxonomy of expressions described in 8.2.1.
57) In C++ class and array prvalues can have cv-qualified types. This differs from ISO C, in which non-lvalues never have
cv-qualified types.
58) This conversion never applies to non-static member functions because an lvalue that refers to a non-static member function
cannot be obtained.
§ 7.4
76
7.5
Qualification conversions
[conv.qual]
1
A cv-decomposition of a type T is a sequence of cvi and Pi such that T is
“cv0 P0 cv1 P1 · · · cvn−1 Pn−1 cvn U” for n > 0,
where each cvi is a set of cv-qualifiers (6.7.3), and each Pi is “pointer to” (11.3.1), “pointer to member of
class Ci of type” (11.3.3), “array of Ni”, or “array of unknown bound of” (11.3.4). If Pi designates an array,
the cv-qualifiers cvi+1 on the element type are also taken as the cv-qualifiers cvi of the array. [ Example: The
type denoted by the type-id const int ** has two cv-decompositions, taking U as “int” and as “pointer to
const int”. — end example ] The n-tuple of cv-qualifiers after the first one in the longest cv-decomposition
of T, that is, cv1, cv2, . . . , cvn, is called the cv-qualification signature of T.
2
Two types T1 and T2 are similar if they have cv-decompositions with the same n such that corresponding Pi
components are the same and the types denoted by U are the same.
3
A prvalue expression of type T1 can be converted to type T2 if the following conditions are satisfied, where cvj
i
denotes the cv-qualifiers in the cv-qualification signature of Tj :59
(3.1)
—
T1 and T2 are similar.
(3.2)
—
For every i > 0, if const is in cv1
and similarly for volatile.
i thenconstisincvi,
(3.3)
—
If the cv1
i andcvi aredifferent,thenconstisineverycvk for0<k<i.
[Note: If a program could assign a pointer of type T** to a pointer of type const T** (that is, if line #1
below were allowed), a program could inadvertently modify a const object (as it is done on line #2). For
example,
int main() {
const char c = ’c’;
char* pc;
const char** pcc = &pc;
// #1: not allowed
*pcc = &c;
*pc = ’C’;
// #2: modifies a const object
}
— end note ]
4
[Note: A prvalue of type “pointer to cv1 T” can be converted to a prvalue of type “pointer to cv2 T” if
“cv2 T” is more cv-qualified than “cv1 T”. A prvalue of type “pointer to member of X of type cv1 T” can be
converted to a prvalue of type “pointer to member of X of type cv2 T” if “cv2 T” is more cv-qualified than
“cv1 T”. — end note ]
5
[Note: Function types (including those used in pointer to member function types) are never cv-qualified
(11.3.5).
— end note ]
7.6
Integral promotions
[conv.prom]
1
A prvalue of an integer type other than bool, char16_t, char32_t, or wchar_t whose integer conversion
rank (6.7.4) is less than the rank of int can be converted to a prvalue of type int if int can represent all the
values of the source type; otherwise, the source prvalue can be converted to a prvalue of type unsigned int.
2
A prvalue of type char16_t, char32_t, or wchar_t (6.7.1) can be converted to a prvalue of the first of
the following types that can represent all the values of its underlying type: int, unsigned int, long int,
unsigned long int, long long int, or unsigned long long int. If none of the types in that list can
represent all the values of its underlying type, a prvalue of type char16_t, char32_t, or wchar_t can be
converted to a prvalue of its underlying type.
3
A prvalue of an unscoped enumeration type whose underlying type is not fixed (10.2) can be converted to a
prvalue of the first of the following types that can represent all the values of the enumeration (i.e., the values
in the range bmin to bmax as described in 10.2): int, unsigned int, long int, unsigned long int, long
long int, or unsigned long long int. If none of the types in that list can represent all the values of the
enumeration, a prvalue of an unscoped enumeration type can be converted to a prvalue of the extended
integer type with lowest integer conversion rank (6.7.4) greater than the rank of long long in which all the
values of the enumeration can be represented. If there are two such extended types, the signed one is chosen.
4
A prvalue of an unscoped enumeration type whose underlying type is fixed (10.2) can be converted to a
prvalue of its underlying type. Moreover, if integral promotion can be applied to its underlying type, a
59) These rules ensure that const-safety is preserved by the conversion.
§ 7.6
77
prvalue of an unscoped enumeration type whose underlying type is fixed can also be converted to a prvalue
of the promoted underlying type.
5
A prvalue for an integral bit-field (12.2.4) can be converted to a prvalue of type int if int can represent all
the values of the bit-field; otherwise, it can be converted to unsigned int if unsigned int can represent all
the values of the bit-field. If the bit-field is larger yet, no integral promotion applies to it. If the bit-field has
an enumerated type, it is treated as any other value of that type for promotion purposes.
6
A prvalue of type bool can be converted to a prvalue of type int, with false becoming zero and true
becoming one.
7
These conversions are called integral promotions.
7.7
Floating-point promotion
[conv.fpprom]
1
A prvalue of type float can be converted to a prvalue of type double. The value is unchanged.
2
This conversion is called floating-point promotion.
7.8
Integral conversions
[conv.integral]
1
A prvalue of an integer type can be converted to a prvalue of another integer type. A prvalue of an unscoped
enumeration type can be converted to a prvalue of an integer type.
2
If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source
integer (modulo 2n where n is the number of bits used to represent the unsigned type). [ Note: In a two’s
complement representation, this conversion is conceptual and there is no change in the bit pattern (if there is
no truncation).
— end note ]
3
If the destination type is signed, the value is unchanged if it can be represented in the destination type;
otherwise, the value is implementation-defined.
4
If the destination type is bool, see 7.14. If the source type is bool, the value false is converted to zero and
the value true is converted to one.
5
The conversions allowed as integral promotions are excluded from the set of integral conversions.
7.9
Floating-point conversions
[conv.double]
1
A prvalue of floating-point type can be converted to a prvalue of another floating-point type. If the
source value can be exactly represented in the destination type, the result of the conversion is that exact
representation. If the source value is between two adjacent destination values, the result of the conversion is
an implementation-defined choice of either of those values. Otherwise, the behavior is undefined.
2
The conversions allowed as floating-point promotions are excluded from the set of floating-point conversions.
7.10
Floating-integral conversions
[conv.fpint]
1
A prvalue of a floating-point type can be converted to a prvalue of an integer type. The conversion truncates;
that is, the fractional part is discarded. The behavior is undefined if the truncated value cannot be represented
in the destination type. [ Note: If the destination type is bool, see 7.14.
— end note ]
2
A prvalue of an integer type or of an unscoped enumeration type can be converted to a prvalue of a floating-
point type. The result is exact if possible. If the value being converted is in the range of values that can
be represented but the value cannot be represented exactly, it is an implementation-defined choice of either
the next lower or higher representable value. [Note: Loss of precision occurs if the integral value cannot
be represented exactly as a value of the floating type.
— end note ] If the value being converted is outside
the range of values that can be represented, the behavior is undefined. If the source type is bool, the value
false is converted to zero and the value true is converted to one.
7.11
Pointer conversions
[conv.ptr]
1
A null pointer constant is an integer literal (5.13.2) with value zero or a prvalue of type std::nullptr_t. A
null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is
distinguishable from every other value of object pointer or function pointer type. Such a conversion is called
a null pointer conversion. Two null pointer values of the same type shall compare equal. The conversion of
a null pointer constant to a pointer to cv-qualified type is a single conversion, and not the sequence of a
pointer conversion followed by a qualification conversion (7.5). A null pointer constant of integral type can
§ 7.11
78
be converted to a prvalue of type std::nullptr_t. [Note: The resulting prvalue is not a null pointer value.
— end note ]
2
A prvalue of type “pointer to cv T”, where T is an object type, can be converted to a prvalue of type “pointer
to cv void”. The pointer value (6.7.2) is unchanged by this conversion.
3
A prvalue of type “pointer to cv D”, where D is a class type, can be converted to a prvalue of type “pointer to
cv B”, where B is a base class (Clause 13) of D. If B is an inaccessible (Clause 14) or ambiguous (13.2) base
class of D, a program that necessitates this conversion is ill-formed. The result of the conversion is a pointer
to the base class subobject of the derived class object. The null pointer value is converted to the null pointer
value of the destination type.
7.12
Pointer-to-member conversions
[conv.mem]
1
A null pointer constant (7.11) can be converted to a pointer-to-member type; the result is the null member
pointer value of that type and is distinguishable from any pointer to member not created from a null pointer
constant. Such a conversion is called a null member pointer conversion. Two null member pointer values of
the same type shall compare equal. The conversion of a null pointer constant to a pointer to member of
cv-qualified type is a single conversion, and not the sequence of a pointer-to-member conversion followed by a
qualification conversion (7.5).
2
A prvalue of type “pointer to member of B of type cv T”, where B is a class type, can be converted to a
prvalue of type “pointer to member of D of type cv T”, where D is a derived class (Clause 13) of B. If B is an
inaccessible (Clause 14), ambiguous (13.2), or virtual (13.1) base class of D, or a base class of a virtual base
class of D, a program that necessitates this conversion is ill-formed. The result of the conversion refers to
the same member as the pointer to member before the conversion took place, but it refers to the base class
member as if it were a member of the derived class. The result refers to the member in D’s instance of B.
Since the result has type “pointer to member of D of type cv T”, indirection through it with a D object is
valid. The result is the same as if indirecting through the pointer to member of B with the B subobject of D.
The null member pointer value is converted to the null member pointer value of the destination type.60
7.13
Function pointer conversions
[conv.fctptr]
1
A prvalue of type “pointer to noexcept function” can be converted to a prvalue of type “pointer to function”.
The result is a pointer to the function. A prvalue of type “pointer to member of type noexcept function”
can be converted to a prvalue of type “pointer to member of type function”. The result points to the member
function.
[ Example:
void (*p)();
void (**pp)() noexcept = &p;
// error: cannot convert to pointer to noexcept function
struct S { typedef void (*p)(); operator p(); };
void (*q)() noexcept = S();
// error: cannot convert to pointer to noexcept function
— end example ]
7.14
Boolean conversions
[conv.bool]
1
A prvalue of arithmetic, unscoped enumeration, pointer, or pointer-to-member type can be converted to a
prvalue of type bool. A zero value, null pointer value, or null member pointer value is converted to false;
any other value is converted to true. For direct-initialization (11.6), a prvalue of type std::nullptr_t can
be converted to a prvalue of type bool; the resulting value is false.
60) The rule for conversion of pointers to members (from pointer to member of base to pointer to member of derived) appears
inverted compared to the rule for pointers to objects (from pointer to derived to pointer to base) (7.11, Clause 13). This inversion
is necessary to ensure type safety. Note that a pointer to member is not an object pointer or a function pointer and the rules for
conversions of such pointers do not apply to pointers to members. In particular, a pointer to member cannot be converted to a
void*.
§ 7.14
79
8
Expressions
[expr]
8.1
Preamble
[expr.pre]
1
[Note: Clause 8 defines the syntax, order of evaluation, and meaning of expressions.61 An expression is a
sequence of operators and operands that specifies a computation. An expression can result in a value and
can cause side effects.
— end note ]
2
[ Note: Operators can be overloaded, that is, given meaning when applied to expressions of class type (Clause
12) or enumeration type (10.2). Uses of overloaded operators are transformed into function calls as described
in 16.5. Overloaded operators obey the rules for syntax and evaluation order specified in 8.5, but the
requirements of operand type and value category are replaced by the rules for function call. Relations between
operators, such as ++a meaning a+=1, are not guaranteed for overloaded operators (16.5).
— end note ]
3
Subclause 8.5 defines the effects of operators when applied to types for which they have not been overloaded.
Operator overloading shall not modify the rules for the built-in operators, that is, for operators applied to
types for which they are defined by this Standard. However, these built-in operators participate in overload
resolution, and as part of that process user-defined conversions will be considered where necessary to convert
the operands to types appropriate for the built-in operator. If a built-in operator is selected, such conversions
will be applied to the operands before the operation is considered further according to the rules in subclause
8.5; see 16.3.1.2, 16.6.
4
If during the evaluation of an expression, the result is not mathematically defined or not in the range of
representable values for its type, the behavior is undefined. [ Note: Treatment of division by zero, forming a
remainder using a zero divisor, and all floating-point exceptions vary among machines, and is sometimes
adjustable by a library function.
— end note ]
5
The values of the floating operands and the results of floating expressions may be represented in greater
precision and range than that required by the type; the types are not changed thereby.62
8.2
Properties of expressions
[expr.prop]
8.2.1
Value category
[basic.lval]
1
Expressions are categorized according to the taxonomy in Figure 1.
expression
glvalue
rvalue
lvalue
xvalue
prvalue
Figure 1 — Expression category taxonomy
(1.1)
—
A glvalue is an expression whose evaluation determines the identity of an object, bit-field, or function.
(1.2)
—
A prvalue is an expression whose evaluation initializes an object or a bit-field, or computes the value of
the operand of an operator, as specified by the context in which it appears.
(1.3)
—
An xvalue is a glvalue that denotes an object or bit-field whose resources can be reused (usually
because it is near the end of its lifetime).
[Example: Certain kinds of expressions involving rvalue
references (11.3.2) yield xvalues, such as a call to a function whose return type is an rvalue reference or
a cast to an rvalue reference type.
— end example ]
(1.4)
—
An lvalue is a glvalue that is not an xvalue.
(1.5)
—
An rvalue is a prvalue or an xvalue.
61) The precedence of operators is not directly specified, but it can be derived from the syntax.
62) The cast and assignment operators must still perform their specific conversions as described in 8.5.3, 8.5.1.9 and 8.5.18.
§ 8.2.1
80
2
Every expression belongs to exactly one of the fundamental classifications in this taxonomy: lvalue, xvalue,
or prvalue. This property of an expression is called its value category. [ Note: The discussion of each built-in
operator in 8.5 indicates the category of the value it yields and the value categories of the operands it expects.
For example, the built-in assignment operators expect that the left operand is an lvalue and that the right
operand is a prvalue and yield an lvalue as the result. User-defined operators are functions, and the categories
of values they expect and yield are determined by their parameter and return types.
— end note ]
3
[ Note: Historically, lvalues and rvalues were so-called because they could appear on the left- and right-hand
side of an assignment (although this is no longer generally true); glvalues are “generalized” lvalues, prvalues
are “pure” rvalues, and xvalues are “eXpiring” lvalues. Despite their names, these terms classify expressions,
not values.
— end note ]
4
[ Note: An expression is an xvalue if it is:
(4.1)
—
the result of calling a function, whether implicitly or explicitly, whose return type is an rvalue reference
to object type,
(4.2)
—
a cast to an rvalue reference to object type,
(4.3)
—
a class member access expression designating a non-static data member of non-reference type in which
the object expression is an xvalue, or
(4.4)
—
a .* pointer-to-member expression in which the first operand is an xvalue and the second operand is a
pointer to data member.
In general, the effect of this rule is that named rvalue references are treated as lvalues and unnamed rvalue
references to objects are treated as xvalues; rvalue references to functions are treated as lvalues whether
named or not. — end note ]
[ Example:
struct A {
int m;
};
A&& operator+(A, A);
A&& f();
A a;
A&& ar = static_cast<A&&>(a);
The expressions f(), f().m, static_cast<A&&>(a), and a + a are xvalues. The expression ar is an lvalue.
— end example ]
5
The result of a prvalue is the value that the expression stores into its context. A prvalue whose result is the
value V is sometimes said to have or name the value V. The result object of a prvalue is the object initialized
by the prvalue; a prvalue that is used to compute the value of an operand of an operator or that has type
cv void has no result object. [ Note: Except when the prvalue is the operand of a decltype-specifier, a prvalue
of class or array type always has a result object. For a discarded prvalue, a temporary object is materialized;
see 8.2.
— end note ] The result of a glvalue is the entity denoted by the expression.
6
Whenever a glvalue expression appears as an operand of an operator that expects a prvalue for that operand,
the lvalue-to-rvalue (7.1), array-to-pointer (7.2), or function-to-pointer (7.3) standard conversions are applied
to convert the expression to a prvalue. [ Note: An attempt to bind an rvalue reference to an lvalue is not such
a context; see 11.6.3.
— end note ] [ Note: Because cv-qualifiers are removed from the type of an expression
of non-class type when the expression is converted to a prvalue, an lvalue expression of type const int can,
for example, be used where a prvalue expression of type int is required.
— end note ] [ Note: There are no
prvalue bit-fields; if a bit-field is converted to a prvalue (7.1), a prvalue of the type of the bit-field is created,
which might then be promoted (7.6).
— end note ]
7
Whenever a prvalue expression appears as an operand of an operator that expects a glvalue for that operand,
the temporary materialization conversion (7.4) is applied to convert the expression to an xvalue.
8
The discussion of reference initialization in 11.6.3 and of temporaries in 15.2 indicates the behavior of lvalues
and rvalues in other significant contexts.
9
Unless otherwise indicated (8.5.1.2), a prvalue shall always have complete type or the void type. A glvalue
shall not have type cv void. [ Note: A glvalue may have complete or incomplete non-void type. Class and
array prvalues can have cv-qualified types; other prvalues always have cv-unqualified types. See 8.2.
— end
note ]
§ 8.2.1
81
|
|