For each operation that is specified as implicitly creating objects,
that operation implicitly creates and starts the lifetime
of zero or more objects of implicit-lifetime types ([basic.types])
in its specified region of storage
if doing so would result in the program having defined behavior.
If no such set of objects would give the program defined behavior,
the behavior of the program is undefined.
[Example 1: void f(){void*p = malloc(sizeof(int)+sizeof(float));
*reinterpret_cast<int*>(p)=0;
*reinterpret_cast<float*>(p)=0.0f; // undefined behavior, cannot create// both int and float in same place} — end example]
After implicitly creating objects within a specified region of storage,
some operations are described as producing a pointer to a
suitable created object ([basic.types]).
These operations select one of the implicitly-created objects
whose address is the address of the start of the region of storage,
and produce a pointer value that points to that object,
if that value would result in the program having defined behavior.
If no such pointer value would give the program defined behavior,
the behavior of the program is undefined.
[Example 1: #include<cstdlib>struct X {int a, b;
~X()=delete; // deleted destructor makes X a non-implicit-lifetime class};
X* make_x(){
X* p =(X*)std::malloc(sizeof(struct X)); // Cannot implicitly create an object because X// is not an implicit-lifetime class.
p->a =1; // undefined behavior, no set of objects give us defined behaviorreturn p;
} — end example]
[Example 2: #include<cstdlib>struct X {int a;
};
struct Y {int x;
};
Y* make_y(){
X* p1 =(X*)std::malloc(sizeof(struct X)); // object #1
p1->a =1;
Y* p2 =(Y*)p1;
p2->x =2; // undefined behavior, p2 points to an in-lifetime object of type X,// which is not similar to Y ([expr.ref])return p2;
} — end example]
[Example 1: structalignas(4) S {};
void make_misaligned(){alignas(S)char s[sizeof(S)+1];
new(&s+1) S(); // undefined behavior, &s+1 will yield a pointer to// a char which is 1 byte away from an address with// an alignment of 4 and so cannot have an alignment of 4} — end example]
For a pointer pointing to an object outside of its lifetime,
behavior is undefined if the object will be or was of a class type
with a non-trivial destructor
and the pointer is used as the operand of a delete-expression.
[Example 1: struct S {float f =0;
~S(){}};
void f(){
S* p =new S;
p->~S();
delete p; // undefined behavior, operand of delete, lifetime has ended and S// has a non-trivial destructor} — end example]
For a pointer pointing to an object outside of its lifetime, behavior is
undefined if the pointer is used to access a non-static data member or call a
non-static member function of the object.
[Example 1: struct S {float f =0;
};
float f(){
S s;
S* p =&s;
s.~S();
return p->f; // undefined behavior, accessing non-static data member after end of lifetime} — end example]
For a pointer pointing to an object outside of its lifetime, behavior is
undefined if the pointer is implicitly converted ([conv.ptr]) to a pointer
to a virtual base class (or base class of a virtual base class).
For a pointer pointing to an object outside of its lifetime, behavior is
undefined if the pointer is used as the operand of a
dynamic_cast ([expr.dynamic.cast]).
[Example 1: struct B {virtual~B()=default; };
struct D : B {};
void f(){
D d;
B* bp =&d;
d.~D();
D* dp =dynamic_cast<D*>(bp); // undefined behavior} — end example]
[Example 1: void f(){int x =int{10};
using T =int;
x.~T();
int y = x; // undefined behavior, glvalue used to access the// object after the lifetime has ended} — end example]
[Example 1: struct A {void f(){}};
void f(){
A a;
a.~A();
a.f(); // undefined behavior, glvalue used to access a non-static member// function after the lifetime has ended} — end example]
Behavior is undefined if a glvalue referring to an object outside of its
lifetime is used as the operand of a
dynamic_cast or as the operand of typeid.
[Example 1: struct B {virtual~B(); };
struct D :virtual B {};
void f(){
D d;
B& br = d;
d.~D();
D& dr =dynamic_cast<D&>(br); // undefined behavior} — end example]
The behavior is undefined if
a non-trivial implicit destructor call
occurs when the type of the object inhabiting the associated storage
is not the original type associated with that storage.
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 1: #include<new>void*operatornew(std::size_t sz){if(sz ==0)returnnullptr; // undefined behavior, should return non-null pointerreturn std::malloc(1); // undefined behavior, if successful should return allocation with// length in bytes is at least as large as the requested size}voidoperatordelete(void* ptr)noexcept{throw0; // undefined behavior, terminates by throwing an exception} — end example]
If a side effect on a memory location ([intro.memory])
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 ([intro.multithread]),
the behavior is undefined.
[Example 1: void g(int i){
i =7, i++, i++; // i becomes 9
i = i+++1; // the value of i is incremented
i = i+++ i; // undefined behavior
i = i +1; // the value of i is incremented} — end example]
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 in [intro.races].
[Example 1: int count =0;
auto f =[&]{ count++; };
std::thread t1{f}, t2{f}, t3{f};
// undefined behavior t1, t2 and t3 have a data race on access of variable count — end example]
[Example 1: bool stop(){returnfalse; }void busy_wait_thread(){while(!stop()); // undefined behavior, thread makes no progress but the loop}// is not trivial because stop() is not a constant expressionint main(){
std::thread t(busy_wait_thread);
t.join();
} — end example]
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.
[Example 1: #include<cstdlib>struct Exiter {~Exiter(){ std::exit(0); }};
Exiter ex;
int main(){}// undefined behavior when destructor of static variable ex is called it will call std::exit — end example]
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.
[Example 1: struct A {};
void f(){static A a;
}struct B {
B(){ f(); }};
struct C {~C(){ f(); }};
C c;
B b; // call to f() in constructor begins lifetime of aint main(){}// undefined behavior, static objects are destructed in reverse order, in this case a then b and// finally c. When the destructor of c is called, it calls f() which passes through the definition of// previously destroyed block-scope object — end example]
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.
[Example 1: #include<limits>int main(){// Assuming 32-bit int, the range of values is: −2,147,483,648 to 2,147,483,647.int x1 = std::numeric_limits<int>::max()+1;
// undefined behavior, 2,147,483,647+1 is not representable as an intint x2 = std::numeric_limits<int>::min()/-1;
// undefined behavior, −2,147,483,648/−1 is not representable as an int} — end example]
If a program attempts to access ([defns.access]) the stored value of an object
whose dynamic type is T through a glvalue
whose type is not similar ([conv.qual]) to T
(or its corresponding signed or unsigned types)
the behavior is undefined.
[Example 1: int foo(float* f, int* i){*i =1;
*f =0.f; // undefined behavior, glvalue is not similar to intreturn*i;
}int main(){int x =0;
x = foo(reinterpret_cast<float*>(&x), &x);
} — end example]
If a program invokes a defaulted copy/move constructor or
defaulted copy/move assignment operator of a union
with an argument that is not an object of a similar type
within its lifetime, the behavior is undefined.
[Example 1: bool f(){bool b =true;
char c =42;
memcpy(&b, &c, 1);
return b; // undefined behavior if 42 is not a valid value representation for bool} — end example]
[Example 1: #include<limits>int main(){// Assuming 32-bit int, 32-bit float and 64-bit double.double d2 = std::numeric_limits<double>::max();
float f = d2; // undefined behavior on systems where the range of representable values// of float is [-max,+max]; on systems where the range of representable// values is [-inf,+inf] this would not be undefined behaviorint i = d2; // undefined behavior, the max value of double is not representable as int} — end example]
[Example 1: #include<limits>int main(){// Assuming 32-bit int, the range of values is: −2,147,483,648 to// 2,147,483,647. Assuming 32-bit float and 64-bit double.double d =(double)std::numeric_limits<int>::max()+1;
int x1 = d; // undefined behavior 2,147,483,647+1 is not representable as int} — end example]
When converting a value of integer or unscoped enumeration type
to a floating-point type,
if the value is not representable in the destination type
the behavior is undefined.
[Example 1: int main(){unsignedlonglong x2 =-1;
float f = x2; // undefined behavior on systems where f does not include// a representation for infinity and the maximum value for float// is smaller than the maximum value for unsigned long long} — end example]
Converting
a pointer to a derived class D
to
a pointer to a virtual base class B
that does not point to
a valid object
within its lifetime
has undefined behavior.
The conversion of
a pointer to a member of a base class
to a pointer to member of a derived class
that could not contain that member
has undefined behavior.
Calling a function through an expression whose
function type is not call-compatible with
the function type of the called
function's definition results in undefined behavior.
[Example 1: using f_float =int(*)(float);
using f_int =int(*)(int);
int f1(float){return10; }int f2(int){return20; }int main(){returnreinterpret_cast<f_int>(f1)(20); // undefined behavior, the function type of the expression// is different from the called functions definition} — end example]
In a class member access E1.E2,
where E2 is a non-static member,
the behavior is undefined
if E1 refers to an object
whose type is not similar
to the type of the expression E1.
Evaluating a dynamic_cast on a non-null pointer
that points to an object (of polymorphic type) of the wrong type
or to an object not within its lifetime
has undefined behavior.
Evaluating a dynamic_cast on a reference
that denotes an object (of polymorphic type)
of a type that is not similar to the referenced type
or an object not within its lifetime
has undefined behavior.
[Example 1: struct B {};
struct D1 : B {};
struct D2 : B {};
void f(){
D1 d;
B &b = d;
static_cast<D2 &>(b); // undefined behavior, base class object of type D1 not D2} — end example]
If the enumeration type does not have a fixed underlying type,
the value is unchanged if the original value
is within the range of the enumeration values ([dcl.enum]),
and otherwise, the behavior is undefined.
[Example 1: enum A { e1 =1, e2 };
void f(){enum A a =static_cast<A>(4); // undefined behavior, 4 is not within the range of enumeration values} — end example]
If float does not adhere to ISO/IEC 60559
and cannot represent positive infinity,
a sufficiently large double value will be
outside the (finite) range of float.
void f(){double d = FLT_MAX;
d *=16;
float f =static_cast<float>(d); // undefined behavior} — end example]
Casting from a pointer to a base class to a pointer to a derived class
when there is no enclosing object of that derived class at the
specified location has undefined behavior.
[Example 1: struct B {};
struct D1 : B {};
struct D2 : B {};
void f(){
B *bp =new D1;
static_cast<D2 *>(bp); // undefined behavior, base class object of type D1 not D2} — end example]
A
pointer to member of derived class D
can be cast to
a pointer to member of base class B
(with certain restrictions on cv qualifiers)
as long as B contains the original member,
or is a base or derived class of the class
containing the original member;
otherwise the behavior is undefined.
[Example 1: struct A {char c;
};
struct B {int i;
};
struct D : A, B {};
int main(){char D::*p1 =&D::c;
char B::*p2 =static_cast<char B::*>(p1); // undefined behavior, B does not contain the original member c} — end example]
[Example 1: #include<new>[[nodiscard]]void*operatornew(std::size_t size, void* ptr)noexcept{returnnullptr; // undefined behavior, should return non-null pointer} — end example]
[Example 2: #include<new>struct A {int x;
};
int main(){char*p =nullptr;
A *a =new(p) A; // undefined behavior, non-allocating new returning nullptr} — end example]
If the static type of the object to be deleted
is different from its dynamic type
and the selected deallocation function
is not a destroying operator delete,
the static type shall be a base class
of the dynamic type of the object to be deleted
and the static type shall have a virtual destructor
or the behavior is undefined.
[Example 1: struct B {};
struct D : B {int x;
};
void f(){
B *b =new B;
D *d =static_cast<D *>(b);
int D::*p =&D::x;
(*d).*p =1; // undefined behavior, dynamic type B does not contain x} — end example]
[Example 1: int main(){int x =1/0; // undefined behavior, division by zerodouble d =1.0/0.0; // undefined behavior on systems where the range of// representable values of double is [-max,+max], on systems where// representable values is [-inf,+inf] this would not be undefined behavior} — end example]
[Example 1: #include<limits>int main(){int x = std::numeric_limits<int>::min()/-1;
// Assuming LP64−2,147,483,648 which when divided by −1// gives us 2,147,483,648 which is not representable by int.} — end example]
[Example 1: staticconstint arrs[10]{};
int main(){constint*y = arrs +11; // undefined behavior, creating an out of bounds pointer} — end example]
[Example 2: staticconstint arrs[10][10]{};
int main(){constint(*y)[10]= arrs +11; // undefined behavior, creating an out of bounds pointer} — end example]
[Example 1: #include<cstddef>void f(){int x[2];
int y[2];
int* p1 = x;
int* p2 = y;
std::ptrdiff_t off = p1 - p2; // undefined behavior, p1 and p2 point to different arrays} — end example]
For addition or subtraction of two expressions P and Q,
if P or Q have type “pointer to cvT”, where T and the array
element type are not similar ([conv.rval]), the behavior is undefined.
[Example 1: struct S {int i; };
struct T : S {double d; };
void f(const S* s, std::size_t count){for(const S* end = s + count; s != end; ++s){// undefined behavior, T is not similar to S but s points to a T[]/* ... */}}int main(){
T test[5];
f(test, 5);
} — end example]
[Example 1: int y =1<<-1; // undefined behavior, shift is negativestatic_assert(sizeof(int)==4&& CHAR_BIT ==8);
int y1 =1<<32; // undefined behavior, shift is equal to the bit width of intint y2 =1>>32; // undefined behavior, shift is equal to the bit width of int — end example]
[Example 1: int f(int x){if(x)return1;
// undefined behavior if x is 0}void b(){int x = f(0); // undefined behavior, using 0 as an argument will cause f(...) to flow// off the end without a return statement} — end example]
Initializing a reference to a function
with a value that is a function
that is not call-compatible ([expr.call])
with the type of the reference
has undefined behavior.
Initializing a reference to an object
with a value that is not
type-accessible ([basic.lval]) through
the type of the reference
has undefined behavior.
Once a destructor is invoked for an object,
the object's lifetime has ended;
the behavior is undefined if the
destructor is invoked for an object whose lifetime has ended.
[Example 1: struct B {virtualvoid f()=0;
B(){
f(); // undefined behavior, f is pure virtual and is being called from the constructor}};
struct D : B {void f()override;
};
— end example]
[Example 1: class A {public:
A(int);
};
class B :public A {int j;
public:int f();
B(): A(f()), // undefined behavior, calls member function but base A not yet initialized
j(f()){}// defined, bases are all initialized};
class C {public:
C(int);
};
class D :public B, C {int i;
public:
D(): C(f()), // undefined behavior, calls member function but base C not yet initialized
i(f()){}// defined, bases are all initialized};
— end example]
For an object with a non-trivial constructor,
referring to any non-static member or base class of the object
before the constructor begins execution results in undefined behavior.
[Example 1: struct W {int j;
};
struct X :publicvirtual W {};
struct Y {int*p;
X x;
Y(): p(&x.j){// undefined behavior, x is not yet constructed}};
— end example]
For an object with a non-trivial destructor,
referring to any non-static member or base class of the object
after the destructor finishes execution
has undefined behavior.
Converting a pointer to a base class of an object,
when construction of that object has not started
or destruction of that object has finished,
has undefined behavior.
[Example 1: struct A {};
struct B :virtual A {};
struct C : B {};
struct D :virtual A { D(A*); };
struct X { X(A*); };
struct E : C, D, X {
E(): D(this), // undefined behavior, upcast from E* to A* might use path E*→D*→A*// but D is not constructed// “D((C*)this)'' would be defined, E*→C* is defined because E() has started,// and C*→A* is defined because C is fully constructed
X(this){}// defined, upon construction of X, C/B/D/A sublattice is fully constructed};
— end example]
When forming a pointer to
a direct non-static member of a class,
construction must have started
and destruction must not have finished
otherwise the behavior is undefined.
When a virtual function is called directly or indirectly
from a constructor or from a destructor,
including during the construction or destruction
of the class's non-static data members,
and the object to which the call applies
is the object (call it x) under construction or destruction,
the function called is the final overrider in the constructor's or destructor's class
and not one overriding it in a more-derived class.
If the virtual function call uses an explicit class member access ([expr.ref])
and the object expression refers to the complete object of x
or one of that object's base class subobjects
but not x or one of its base class subobjects,
the behavior is undefined.
[Example 1: struct V {virtualvoid f();
virtualvoid g();
};
struct A :virtual V {virtualvoid f();
};
struct B :virtual V {virtualvoid g();
B(V *, A *);
};
struct D : A, B {virtualvoid f();
virtualvoid g();
D(): B((A *)this, this){}};
B::B(V *v, A *a){
f(); // calls V::f, not A::f
g(); // calls B::g, not D::g
v->g(); // v is base of B, the call is defined, calls B::g
a->f(); // undefined behavior, a's type not a base of B} — end example]
If the operand of typeid refers to
the object under construction or destruction and the static type of the operand is neither the constructor or
destructor's class nor one of its bases, the behavior is undefined.
[Example 1: struct V {virtualvoid f();
};
struct A :virtual V {};
struct B :virtual V {
B(V *, A *);
};
struct D : A, B {
D(): B((A *)this, this){}};
B::B(V *v, A *a){typeid(*this); // std::type_info for Btypeid(*v); // defined, *v has type V, a base of B yields std::type_info for Btypeid(*a); // undefined behavior, type A not a base of B} — end example]
If the operand of the dynamic_cast
refers to the object under construction or destruction
and the static type of the operand
is not a pointer to or object of
the constructor or destructor's own class or one of its bases,
the dynamic_cast results in undefined behavior.
[Example 1: struct V {virtualvoid f();
};
struct A :virtual V {};
struct B :virtual V {
B(V *, A *);
};
struct D : A, B {
D(): B((A *)this, this){}};
B::B(V *v, A *a){dynamic_cast<B *>(v); // defined, v of type V*, V base of B results in B*dynamic_cast<B *>(a); // undefined behavior, a has type A*, A not a base of B} — end example]
[Example 1: template<class T>class X {
X<T>*p; // OK
X<T *> a; // implicit instantiation of X<T> requires// the implicit instantiation of X<T*> which requires// the implicit instantiation of X<T**> which …};
int main(){
X<int> x; // undefined behavior, instantiation will lead to infinite recursion} — end example]
Referring to any non-static member or base class of an object
in the handler for a function-try-block
of a constructor or destructor for that object
results in undefined behavior.
[Example 1: #include<iostream>struct A {
A()try: x(0?1:throw1){}catch(int){
std::cout <<"y: "<< y << std::endl; // undefined behavior, referring to non-static member y in// the handler of function-try-block}int x;
int y =42;
};
— end example]