Undefined Behaviorsuggest change
What is undefined behavior (UB)? According to the ISO C++ Standard (§1.3.24, N4296), it is “behavior for which this International Standard imposes no requirements.”
This means that when a program encounters UB, it is allowed to do whatever it wants. This often means a crash, but it may simply do nothing, make demons fly out of your nose, or even appear to work properly!
Needless to say, you should avoid writing code that invokes UB.
If a program contains undefined behavior, the C++ standard places no constraints on its behavior.
- It may appear to work as the developer intended, but it may also crash or produce strange results.
- The behavior may vary between runs of the same program.
- Any part of the program may malfunction, including lines that come before the line that contains undefined behavior.
- The implementation is not required to document the result of undefined behavior.
An implementation may document the result of an operation that produces undefined behavior according to the standard, but a program that depends on such documented behavior is not portable.
Why undefined behavior exists
Intuitively, undefined behavior is considered a bad thing as such errors can’t be handled graciously through, say, exception handlers.
But leaving some behavior undefined is actually an integral part of C++‘s promise “you don’t pay for what you don’t use”. Undefined behavior allows a compiler to assume the developer knows what he’s doing and not introduce code to check for the mistakes highlighted in the above examples.
Finding and avoiding undefined behavior
Some tools can be used to discover undefined behavior during development:
- Most compilers have warning flags to warn about some cases of undefined behavior at compile time.
- Newer versions of gcc and clang include a so-called “Undefined Behavior Sanitizer” flag (
-fsanitize=undefined) that will check for undefined behavior at runtime, at a performance cost.
lint-like tools may perform more thorough undefined behavior analysis.
Undefined, unspecified and implementation-defined behavior
From C++14 standard (ISO/IEC 14882:2014) section 1.9 (Program Execution):
- The semantic descriptions in this International Standard define a parameterized nondeterministic abstract machine. [CUT]
- Certain aspects and operations of the abstract machine are described in this International Standard as implementation-defined (for example,
sizeof(int)). These constitute the parameters of the abstract machine. Each implementation shall include documentation describing its characteristics and behavior in these respects. [CUT]
- Certain other aspects and operations of the abstract machine are described in this International Standard as unspecified (for example, evaluation of expressions in a new-initializer if the allocation function fails to allocate memory). Where possible, this International Standard defines a set of allowable behaviors. These define the nondeterministic aspects of the abstract machine. An instance of the abstract machine can thus have more than one possible execution for a given program and a given input.
- Certain other operations are described in this International Standard as undefined (or example, the effect of attempting to modify a
constobject). [ Note: this International Standard imposes no requirements on the behavior of programs that contain undefined behavior. —end note ]