C++ Temporary Lifetime Extension With Const References
In C++, temporary objects normally destruct at the end of the
full-expression in which they are created. However, the C++ standard
provides a mechanism where binding a temporary object to a
const lvalue reference (or an rvalue reference) extends the
temporary's lifetime to match the lifetime of the reference itself. This
article covers the specific conditions required for this extension to
occur, how it applies to sub-objects, and the critical edge cases where
lifetime extension fails.
Core Conditions for Lifetime Extension
For lifetime extension to take place, the temporary object must satisfy the following criteria:
Direct Initialization of a Reference: The temporary must be directly bound to a reference to
const(or aconst&&/&&rvalue reference) during the reference's declaration.const std::string& ref = std::string("Hello"); // Lifetime extended to match 'ref'Local Scope Association: The reference must be an automatic (local) variable, a namespace-scope variable, or a
staticvariable. The temporary persists until the reference goes out of scope or the program terminates.
Extension with Sub-Objects and Member Access
Lifetime extension recursively applies when referencing a sub-object of a temporary:
Direct Member Access: If a
constreference binds to a public data member of a temporary class or aggregate, the lifetime of the entire containing temporary object is extended.struct Pair { int a; std::string b; }; const std::string& ref = Pair{1, "Data"}.b; // Entire Pair object's lifetime is extendedArray Elements: If an array temporary is indexed, binding a reference to an element extends the lifetime of the entire temporary array.
Conditional Operator Exceptions
When using the ternary conditional operator (?:), the
lifetime of a temporary operand is extended if the conditional
expression evaluates to that temporary and binds to a reference:
const std::string& ref = condition ? std::string("A") : std::string("B");
// Whichever temporary is selected has its lifetime extended to match 'ref'Situations Where Lifetime Extension Does Not Apply
The C++ standard explicitly defines boundaries where lifetime extension does not occur, often leading to dangling references:
- Function Parameters: A temporary passed by
const&to a function has its lifetime extended only until the end of the full-expression evaluating the function call. It does not persist within the function beyond that call. - Function Return Values: Returning a reference to a temporary created inside a function does not extend the temporary's lifetime outside the function scope. The object is destroyed upon function exit, returning a dangling reference.
- Class Member Initializers: Binding a temporary to a reference member within a constructor's member initializer list does not extend the temporary's lifetime to match the containing class instance. The temporary is destroyed immediately upon completion of the constructor, leaving the member reference dangling.
- Dynamic Allocation (
new): In anewexpression, binding a temporary to a reference member of the dynamically allocated object extends the temporary only until the end of the full-expression containing thenewoperator, not until the object is deleted. - Transitive Function Calls: If a temporary is passed
to a function that returns a reference to that temporary, binding the
result to a
constreference does not extend the original temporary's lifetime; it destructs at the end of the statement.