6 Basics [basic]

6.7 Memory and objects [basic.memobj]

6.7.7 Temporary objects [class.temporary]

Temporary objects are created
  • when a prvalue is converted to an xvalue ([conv.rval]) and
  • when needed by the implementation to pass or return an object of trivially copyable type (see below).
Even when the creation of the temporary object is unevaluated ([expr.context]), all the semantic restrictions shall be respected as if the temporary object had been created and later destroyed.
[Note 1: 
This includes accessibility ([class.access]) and whether it is deleted, for the constructor selected and for the destructor.
However, in the special case of the operand of a decltype-specifier ([dcl.type.decltype]), no temporary is introduced, so the foregoing does not apply to such a prvalue.
— end note]
The materialization of a temporary object is generally delayed as long as possible in order to avoid creating unnecessary temporary objects.
[Note 2: 
Temporary objects are materialized:
— end note]
[Example 1: 
Consider the following code: class X { public: X(int); X(const X&); X& operator=(const X&); ~X(); }; class Y { public: Y(int); Y(Y&&); ~Y(); }; X f(X); Y g(Y); void h() { X a(1); X b = f(X(2)); Y c = g(Y(3)); a = f(a); }
X(2) is constructed in the space used to hold f()'s argument and Y(3) is constructed in the space used to hold g()'s argument.
Likewise, f()'s result is constructed directly in b and g()'s result is constructed directly in c.
On the other hand, the expression a = f(a) requires a temporary for the result of f(a), which is materialized so that the reference parameter of X​::​operator=(const X&) can bind to it.
— end example]
When an object of class type X is passed to or returned from a potentially-evaluated function call, if X has at least one eligible copy or move constructor ([special]), each such constructor is trivial, and the destructor of X is either trivial or deleted, implementations are permitted to create a temporary object to hold the function parameter or result object.
The temporary object is constructed from the function argument or return value, respectively, and the function's parameter or return object is initialized as if by using the eligible trivial constructor to copy the temporary (even if that constructor is inaccessible or would not be selected by overload resolution to perform a copy or move of the object).
[Note 3: 
This latitude is granted to allow objects of class type to be passed to or returned from functions in registers.
— end note]
Temporary objects are destroyed as the last step in evaluating the full-expression ([intro.execution]) that (lexically) contains the point where they were created.
This is true even if that evaluation ends in throwing an exception.
The value computations and side effects of destroying a temporary object are associated only with the full-expression, not with any specific subexpression.
There are five contexts in which temporaries are destroyed at a different point than the end of the full-expression.
The first context is when a default constructor is called to initialize an element of an array with no corresponding initializer ([dcl.init]).
The second context is when a copy constructor is called to copy an element of an array while the entire array is copied ([expr.prim.lambda.capture], [class.copy.ctor]).
In either case, if the constructor has one or more default arguments, the destruction of every temporary created in a default argument is sequenced before the construction of the next array element, if any.
The third context is when a reference binds to a temporary object.26
The temporary object to which the reference is bound or the temporary object that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference if the glvalue to which the reference is bound was obtained through one of the following:
  • a temporary materialization conversion ([conv.rval]),
  • ( expression ), where expression is one of these expressions,
  • subscripting ([expr.sub]) of an array operand, where that operand is one of these expressions,
  • a class member access ([expr.ref]) using the . operator where the left operand is one of these expressions and the right operand designates a non-static data member of non-reference type,
  • a pointer-to-member operation ([expr.mptr.oper]) using the .* operator where the left operand is one of these expressions and the right operand is a pointer to data member of non-reference type,
  • a converting, without a user-defined conversion, a glvalue operand that is one of these expressions to a glvalue that refers to the object designated by the operand, or to its complete object or a subobject thereof,
  • a conditional expression ([expr.cond]) that is a glvalue where the second or third operand is one of these expressions, or
  • a comma expression ([expr.comma]) that is a glvalue where the right operand is one of these expressions.
[Example 2: template<typename T> using id = T; int i = 1; int&& a = id<int[3]>{1, 2, 3}[i]; // temporary array has same lifetime as a const int& b = static_cast<const int&>(0); // temporary int has same lifetime as b int&& c = cond ? id<int[3]>{1, 2, 3}[i] : static_cast<int&&>(0); // exactly one of the two temporaries is lifetime-extended — end example]
[Note 4: 
An explicit type conversion ([expr.type.conv], [expr.cast]) is interpreted as a sequence of elementary casts, covered above.
[Example 3: const int& x = (const int&)1; // temporary for value 1 has same lifetime as x — end example]
— end note]
[Note 5: 
If a temporary object has a reference member initialized by another temporary object, lifetime extension applies recursively to such a member's initializer.
[Example 4: struct S { const int& m; }; const S& s = S{1}; // both S and int temporaries have lifetime of s — end example]
— end note]
The exceptions to this lifetime rule are:
  • A temporary object bound to a reference parameter in a function call ([expr.call]) persists until the completion of the full-expression containing the call.
  • A temporary object bound to a reference element of an aggregate of class type initialized from a parenthesized expression-list ([dcl.init]) persists until the completion of the full-expression containing the expression-list.
  • A temporary bound to a reference in a new-initializer ([expr.new]) persists until the completion of the full-expression containing the new-initializer.
    [Note 6: 
    This might introduce a dangling reference.
    — end note]
    [Example 5: struct S { int mi; const std::pair<int,int>& mp; }; S a { 1, {2,3} }; S* p = new S{ 1, {2,3} }; // creates dangling reference — end example]
The fourth context is when a temporary object is created in the for-range-initializer of a range-based for statement.
If such a temporary object would otherwise be destroyed at the end of the for-range-initializer full-expression, the object persists for the lifetime of the reference initialized by the for-range-initializer.
The fifth context is when a temporary object is created in a structured binding declaration ([dcl.struct.bind]).
Any temporary objects introduced by the initializers for the variables with unique names are destroyed at the end of the structured binding declaration.
Let x and y each be either a temporary object whose lifetime is not extended, or a function parameter.
If the lifetimes of x and y end at the end of the same full-expression, and x is initialized before y, then the destruction of y is sequenced before that of x.
If the lifetime of two or more temporaries with lifetimes extending beyond the full-expressions in which they were created ends at the same point, these temporaries are destroyed at that point in the reverse order of the completion of their construction.
In addition, the destruction of such temporaries shall take into account the ordering of destruction of objects with static, thread, or automatic storage duration ([basic.stc.static], [basic.stc.thread], [basic.stc.auto]); that is, if obj1 is an object with the same storage duration as the temporary and created before the temporary is created the temporary shall be destroyed before obj1 is destroyed; if obj2 is an object with the same storage duration as the temporary and created after the temporary is created the temporary shall be destroyed after obj2 is destroyed.
[Example 6: struct S { S(); S(int); friend S operator+(const S&, const S&); ~S(); }; S obj1; const S& cr = S(16)+S(23); S obj2;
The expression S(16) + S(23) creates three temporaries: a first temporary T1 to hold the result of the expression S(16), a second temporary T2 to hold the result of the expression S(23), and a third temporary T3 to hold the result of the addition of these two expressions.
The temporary T3 is then bound to the reference cr.
It is unspecified whether T1 or T2 is created first.
On an implementation where T1 is created before T2, T2 shall be destroyed before T1.
The temporaries T1 and T2 are bound to the reference parameters of operator+; these temporaries are destroyed at the end of the full-expression containing the call to operator+.
The temporary T3 bound to the reference cr is destroyed at the end of cr's lifetime, that is, at the end of the program.
In addition, the order in which T3 is destroyed takes into account the destruction order of other objects with static storage duration.
That is, because obj1 is constructed before T3, and T3 is constructed before obj2, obj2 shall be destroyed before T3, and T3 shall be destroyed before obj1.
— end example]
26)26)
The same rules apply to initialization of an initializer_list object ([dcl.init.list]) with its underlying temporary array.