Every object has a lifetime in which it can be used in a well-defined manner. The lifetime of an object begins when sufficient, properly - aligned storage has been obtained for it , and its initialization is complete. The lifetime of an object ends when a nontrivial destructor, if any, is called for the object , and the storage for the object has been reused or released. Use of an object, or a pointer to an object, outside of its lifetime frequently results in undefined behavior.
...
Do not use an object outside of its lifetime , except in the ways described above as being well-defined.
...
An improved compliant solution would not dynamically allocate memory directly , but would instead use an automatic local variable to obtain the storage and perform initialization. If a pointer was were required, use of a smart pointer like such as std::unique_ptr
would be a marked improvement. However, these suggested compliant solutions would distract from the lifetime demonstration of this compliant solution , and are consequently not shown.
...
Code Block | ||||
---|---|---|---|---|
| ||||
struct B {}; struct D1 : virtual B {}; struct D2 : virtual B {}; struct S : D1, D2 {}; void f(const B *b) {} void g() { S *s = new S; // Use s delete s; f(s); } |
Despite the fact that f()
never makes use of the object, the fact that it is its being passed as an argument to f()
is sufficient to trigger undefined behavior.
...
In this noncompliant code example, the function g()
returns a lambda, which captures the automatic local variable i
by reference. When that lambda is returned from the call, the reference it captured will refer to a variable whose lifetime has ended. As a result, when the lambda is executed in f()
, the use of the dangling reference in the lambda results in undefined behavior. As a general rule of thumb, functions returning lambdas should not capture by reference.
...
In this compliant solution, the lambda does not capture i
by reference , but instead captures it by copy. Consequently, the lambda contains an implicit data member named i
whose lifetime is that of the lambda.
...
A std::initializer_list<>
object is constructed from an initializer list as if though the implementation allocated a temporary array and passed it to the std::initializer_list<>
constructor. This temporary array has the same lifetime as other temporary objects , except that initializing a std::initializer_list<>
object from the array extends the lifetime of the array exactly like binding a reference to a temporary [ISO/IEC 14882-2014]. In this noncompliant code example, a member variable of type std::initializer_list<int>
is list-initialized within the constructor's ctor-initializier. Under these circumstances, the conceptual temporary array's lifetime ends once the constructor exits, and so accessing any elements of the std::initializer_list<int>
member variable results in undefined behavior.
...
In this compliant solution, the std::initializer_list<int>
member variable is replaced with a std::vector<int>
, which copies the elements of the initializer list to the container instead of relying on a dangling reference to the temporary array.:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <initializer_list> #include <iostream> #include <vector> class C { std::vector<int> L; public: C() : L{1, 2, 3} {} int first() const { return *L.begin(); } }; void f() { C c; std::cout << c.first(); } |
...
In this noncompliant code example, a lamdba object is stored in a function object, which is later called (executing the lambda) to obtain a constant reference to a value. The lambda object returns an int
value, which is then stored in a temporary int
object that becomes bound to the const int &
return type specified by the function object. However, the temporary object's lifetime is not extended past the return from the function object's invocation, which results in causes undefined behavior when the resulting value is accessed.
...
In this compliant solution, the std::function
object returns an int
instead of a const int &
, ensuring that the value is copied instead of bound to a temporary reference. An alternative solution would be to call the lambda directly , instead of through the std::function
object.
...
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
Clang |
| -Wdangling-initializer-list | Catches some lifetime issues related to incorrect use of std::initializer_list<> |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
...