| Start |
|---|
Reading or writing through a null pointer This is undefined behavior, because a null pointer does not point to any valid object, so there is no object at Although this most often causes a segmentation fault, it is undefined and anything can happen. |
Using an uninitialized local variable This results in undefined behavior, because It is often, incorrectly, claimed that this is because the value is "indeterminate", or "whatever value was in that memory location before". However, it is the act of accessing the value of Although highly unlikely in practice (since it is reliant on specific hardware support) the compiler could equally well electrocute the programmer when compiling the code sample above. With such a compiler and hardware support, such a response to undefined behaviour would markedly increase average (living) programmer understanding of the true meaning of undefined behaviour - which is that the standard places no constraint on the resultant behaviour. Using an indeterminate value of
or if the value is discarded. In such cases, the indeterminate value simply propagates to the result of the expression, if applicable. Note that a |
| Accessing an out-of-bounds index It is undefined behavior to access an index that is out of bounds for an array (or standard library container for that matter, as they are all implemented using a raw array): It is allowed to have a pointer pointing to the end of the array (in this case In general, you're not allowed to create an out-of-bounds pointer. A pointer must point to an element within the array, or one past the end. |
Deleting a derived object via a pointer to a base class that doesn't have a virtual destructor. In section [expr.delete] §5.3.5/3 the standard says that if if the static type of the object to be deleted is different from its dynamic type, 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. This is the case regardless of the question whether the derived class added any data members to the base class. |
Extending the std or posix Namespace The standard (17.6.4.2.1/1) (opens new window) generally forbids extending the The behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a namespace within namespace std unless otherwise specified. The same goes for The behavior of a C++ program is undefined if it adds declarations or definitions to namespace posix or to a namespace within namespace posix unless otherwise specified. Consider the following: Nothing in the standard forbids So, in general, this is forbidden. There are specific exceptions allowed (opens new window), though. Perhaps most usefully, it is allowed to add specializations for user defined types. So, for example, suppose your code has Then the following is fine |
| No return statement for a function with a non-void return type Omitting the Most modern day compilers emit a warning at compile time for this kind of undefined behavior. Note: |
Integer division by zero Division by However: Most implementation implement IEEE-754, which defines floating point division by zero to return |
| Accessing a dangling reference It is illegal to access a reference to an object that has gone out of scope or been otherwise destroyed. Such a reference is said to be dangling since it no longer refers to a valid object. In this example, the local variable |
| Invalid pointer arithmetic The following uses of pointer arithmetic cause undefined behavior: Any pointer arithmetic where either operand's pointee type does not match the dynamic type of the object pointed to (ignoring cv-qualification). According to the standard, "[in] particular, a pointer to a base class cannot be used for pointer arithmetic when the array contains objects of a derived class type." |
Signed Integer Overflow 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. (C++11 Standard paragraph 5/4) This is one of the more nasty ones, as it usually yields reproducible, non-crashing behavior so developers may be tempted to rely heavily on the observed behavior. On the other hand: is well defined since: Unsigned integers, declared unsigned, shall obey the laws of arithmetic modulo (C++11 Standard paragraph 3.9.1/4) Sometimes compilers may exploit an undefined behavior and optimize Here since a signed integer overflow is not defined, compiler is free to assume that it may never happen and hence it can optimize away the "if" block |
| Incorrect pairing of memory allocation and deallocation An object can only be deallocated by An object can only be deallocated by If the argument to Such issues can be avoided by completely avoiding |
| Shifting by an invalid number of positions For the built-in shift operator, the right operand must be nonnegative and strictly less than the bit width of the promoted left operand. Otherwise, the behavior is undefined. |
| Multiple non-identical definitions (the One Definition Rule) If a class, enum, inline function, template, or member of a template has external linkage and is defined in multiple translation units, all definitions must be identical or the behavior is undefined according to the One Definition Rule (ODR) (opens new window).
The above program exhibits undefined behavior because it contains two definitions of the class |
| Modifying a const object Any attempt to modify a Such an attempt can be made through A compiler will usually inline the value of a The following program conceals a far more subtle error: In this code, Despite its name, Therefore, undefined behavior occurs even though there are no obviously dangerous constructs in this program. |
Modifying a string literal
The initialisation of The above example is illegal, and results in a compiler diagnostic, in C++11 and later. A similar example may be constructed to exhibit undefined behaviour by explicitly permitting the type conversion, such as: |
| Accessing an object as the wrong type In most cases, it is illegal to access an object of one type as though it were a different type (disregarding cv-qualifiers). Example: The result is undefined behavior. There are some exceptions to this strict aliasing rule:
A related rule is that if a non-static member function is called on an object that does not actually have the same type as the defining class of the function, or a derived class, then undefined behavior occurs. This is true even if the function does not access the object. |
| Overflow during conversion to or from floating point type If, during the conversion of:
the source value is outside the range of values that can be represented in the destination type, the result is undefined behavior. Example: |
| Returning from a [[noreturn]] function Example from the Standard, [dcl.attr.noreturn]: |
| Infinite template recursion Example from the Standard, [temp.inst]/17: |
| Floating point overflow If an arithmetic operation that yields a floating point type produces a value that is not in the range of representable values of the result type, the behavior is undefined according to the C++ standard, but may be defined by other standards the machine might conform to, such as IEEE 754. |
| Calling (Pure) Virtual Members From Constructor Or Destructor The Standard (10.4) (opens new window) states: Member functions can be called from a constructor (or destructor) of an abstract class; the effect of making a virtual call (10.3) to a pure virtual function directly or indirectly for the object being created (or destroyed) from such a constructor (or destructor) is undefined. More generally, some C++ authorities, e.g. Scott Meyers, suggest (opens new window) never calling virtual functions (even non-pure ones) from constructors and dstructors. Consider the following example, modified from the above link: Suppose we create a This implicitly calls the constructor of Consequently, the call in |
| Invalid base-to-derived static cast If |
| Function call through mismatched function pointer type In order to call a function through a function pointer, the function pointer's type must exactly match the function's type. Otherwise, the behaviour is undefined. Example: |
| Access to nonexistent member through pointer to member When accessing a non-static member of an object through a pointer to member, if the object does not actually contain the member denoted by the pointer, the behavior is undefined. (Such a pointer to member can be obtained through |
| Invalid derived-to-base conversion for pointers to members When |
| Destroying an object that has already been destroyed In this example, a destructor is explicitly invoked for an object that will later be automatically destroyed. A similar issue occurs when a Another way to destroy an object twice is by having two RemarksIf a program contains undefined behavior, the C++ standard places no constraints on its 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:
Undefined, unspecified and implementation-defined (opens new window) behavior From C++14 standard (ISO/IEC 14882:2014) section 1.9 (Program Execution):
|
Read Article
https://develop.horje.com/learn/1434/reference