N3918
Jens Maurer
2014-02-12

N3918: Core Issue 1299: Temporary objects vs temporary expressions

This paper presents the propoosed wording for core issue 1299.

The term "temporary object" is consistently applied, and wording is added to define a "temporary expression" as one that permits lifetime extension. The exception object is no longer a "temporary" in that sense (see 15.1 except.throw), since there is no relationship to the other temporary objects mentioned in the standard; the lifetime of the exception object is defined in 15.1 except.throw, not in 12.2 class.temporary.

The drafting below also addresses core issues 943, 1076, and 1300.

Proposed wording

Change in 3.6.2 basic.start.init paragraph 2:
Change in 4.1 conv.lval paragraph 2:
Insert a new paragraph before 5 expr paragraph 10:
An expression may be a temporary expression, in which case the lifetime of its temporary object (if any) may be extended (12.2 class.temporary).
Change in 5.1.2 expr.prim.lambda paragraph 2:
A lambda-expression is a prvalue temporary expression. Its value is a temporary object The evaluation of a lambda-expression results in a prvalue temporary (12.2 class.temporary). This temporary is called the closure object. ...
Change in 5.2.1 expr.sub paragraph 1:
... The expression E1[E2] is identical (by definition) to *((E1)+(E2)) [ Note: see 5.3 and 5.7 for details of * and + and 8.3.4 for details of arrays. -- end note ], except that in the case of an array operand:
Change in 5.2.2 expr.call paragraph 11:
If a function call is a prvalue of object type:
Replace the entirety of 5.2.3 expr.type.conv as follows:

A simple-type-specifier (7.1.6.2 dcl.type.simple) or typename-specifier (14.6 temp.res) designating a type T followed by a braced-init-list or a parenthesized expression-list constructs a value of the specified type T given the expression list. If the In the case of an expression list is with a single expression e, the type conversion expression is equivalent (in definedness, and if defined in meaning) to the corresponding cast expression (T)(e) (5.4 expr.cast). The expression T(), where T is (possibly cv-qualified) void, creates a prvalue of void type.

Otherwise, T shall be an object type or a reference to such a type. If T is a class type or reference to class type, the class type shall be complete. The result of the conversion expression is a value of type T direct-initialized (8.5 dcl.init) with the braced-init-list or parenthesized expression-list as the initializer. If T is an lvalue reference, the result is an lvalue; if T is an rvalue reference, the result is an xvalue; otherwise, the result is a prvalue. If T is an array or class type or a reference to such a type, the result is a temporary object and the conversion expression is a temporary expression.

If the type specified is a class type, the class type shall be complete. If the expression list specifies more than a single value, the type shall be a class with a suitably declared constructor (8.5 dcl.init, 12.1 class.ctor), and the expression T(x1, x2, ...) is equivalent in effect to the declaration T t(x1, x2, ...); for some invented temporary variable t, with the result being the value of t as a prvalue.

The expression T(), where T is a simple-type-specifier or typename-specifier for a non-array complete object type or the (possibly cv-qualified) void type, creates a prvalue of the specified type, whose value is that produced by value-initializing (8.5 dcl.init) an object of type T; no initialization is done for the void() case. [ Note: if T is a non-class type that is cv-qualified, the cv-qualifiers are discarded when determining the type of the resulting prvalue (Clause 5). -- end note ]

Similarly, a simple-type-specifier or typename-specifier followed by a braced-init-list creates a temporary object of the specified type direct-list-initialized (8.5.4 dcl.init.list) with the specified braced-init-list, and its value is that temporary object as a prvalue.

Drafting note: As a change to the status quo, this makes A() valid, where A is an array type.

Change in 5.2.5 expr.ref paragraph 4:

... If E1 is a temporary expression and E2 does not designate a bit-field, then E1.E2 is a temporary expression. If E1 is an lvalue, then E1.E2 is an lvalue; otherwise E1.E2 is an xvalue. ...
Change in 5.2.7 expr.dynamic.cast paragraph 2:
If T is a pointer type, v shall be a prvalue of a pointer to complete class type, and the result is a prvalue of type T. If T is an lvalue reference type, v shall be an lvalue of a complete class type, and the result is an lvalue of the type referred to by T. If T is an rvalue reference type, v shall be an expression having a complete class type, and the result is an xvalue of the type referred to by T. If v is a temporary expression and T is a reference type, the result is a temporary expression.
Change in 5.2.9 expr.static.cast paragraph 1:
The result of the expression static_cast<T>(v) is the result of converting the expression v to type T. If T is an lvalue reference type or an rvalue reference to function type, the result is an lvalue; if T is an rvalue reference to object type, the result is an xvalue; otherwise, the result is a prvalue. If v is a temporary expression and T is "reference to U", where U is reference-compatible with the type of v (8.5.3 dcl.init.ref), the result is a temporary expression. The static_cast operator shall not cast away constness (5.2.11 expr.const.cast).
Change in 5.2.9 expr.static.cast paragraph 4:
... The expression e is used as a glvalue if and only if the initialization uses it as a glvalue. If T is a class type, the static_cast is a temporary expression whose value is the temporary object t.
Change in 5.2.10 expr.reinterpret.cast paragraph 1:
... If v is a temporary expression and T is a reference type, the result is a temporary expression. Conversions that can be performed explicitly using reinterpret_cast are listed below. No other conversion can be performed explicitly using reinterpret_cast.
Change in 5.2.11 expr.const.cast paragraph 4:
... The result of a reference const_cast refers to the original object; the result is a temporary expression if the operand is a temporary expression.
Change in 5.5 expr.mptr.oper paragraph 6:
[ Example: ... ] In a .* expression whose object expression If E1 is an rvalue, the program is ill-formed if the second operand E2 is a pointer to member function with ref-qualifier &. In a .* expression whose object expression If E1 is an lvalue, the program is ill-formed if the second operand E2 is a pointer to member function with ref-qualifier &&. If E1 is a temporary expression and E2 is a pointer to data member, then E1.*E2 is a temporary expression. The result of a .* expression whose second operand E1.*E2 where E2 is a pointer to a data member is an lvalue if the first operand E1 is an lvalue and an xvalue otherwise. The result of a .* expression whose second operand If E2 is a pointer to a member function, the result is a prvalue. If the second operand E2 is the null pointer to member value (4.11 conv.mem), the behavior is undefined.
Change in 5.16 expr.cond paragraph 2:
If either the second or the third operand has type void, one of the following shall hold:
Change in 5.16 expr.cond paragraph 3:
Change in 5.16 expr.cond paragraph 4:
If the second and third operands are glvalues of the same value category and have the same type, the result is of that type and value category and it is a bit-field if the second or the third operand is a bit-field, or if both are bit-fields. The conditional-expression is a temporary expression if the second or third operands, or both, are temporary expressions.
Change in 5.16 expr.cond paragraph 6:
...
Change in 5.18 expr.comma paragraph 1:
... If the value of the right operand is a temporary (12.2 class.temporary), the result is that temporary right operand is a temporary expression, the comma expression is a temporary expression.
Change in 8.5 dcl.init paragraph 17:
Change in 8.5.3 dcl.init.ref paragraph 5:
In all cases except the last (i.e., creating and initializing a temporary object from the initializer expression), the reference is said to bind directly to the initializer expression.
Change in 12.2 class.temporary paragraph 1:
Temporaries Temporary objects of class or array type are created in various contexts: binding a reference to a prvalue (8.5.3 dcl.init.ref), returning a prvalue (6.6.3 stmt.return), a conversion that creates a prvalue (4.1 conv.lval, 5.2.9 expr.static.cast, 5.2.11 expr.const.cast, 5.4 expr.cast), throwing an exception (15.1 except.throw), entering a handler (15.3 except.handle), and in some initializations (8.5 dcl.init). [ Note: The lifetime of exception objects is described in 15.1 except.throw. -- end note ] ...
Change in 12.2 class.temporary paragraph 3:
... Similarly, the destructor shall be called for a temporary object with a non-trivial destructor (12.4 class.dtor). ...
Change in 12.2 class.temporary paragraph 4:
There are two 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. If the constructor has one or more default arguments, the destruction of every temporary object created in a default argument is sequenced before the construction of the next array element, if any.
Change in 12.2 class.temporary paragraph 5:
The second context is when a reference does not bind directly (8.5.3 dcl.init.ref) or is initialized with a temporary expression (clause 5 expr) bound to a temporary. [ Footnote: ... ] The corresponding temporary object (if any) to which the reference is bound or the temporary that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference except: The destruction of a temporary object whose lifetime is not extended by being bound to a reference is sequenced before the destruction of every temporary object which is constructed earlier in the same full-expression. If the lifetime of two or more temporaries temporary objects to which references are bound ends at the same point, these temporaries objects are destroyed at that point in the reverse order of the completion of their construction. In addition, the destruction of temporaries temporary objects bound to references shall take into account the ordering of destruction of objects with static, thread, or automatic storage duration (3.7.1, 3.7.2, 3.7.3); that is, if obj1 is an object with the same storage duration as the a temporary object t and created before the temporary t is created, t the temporary shall be destroyed before obj1 is destroyed; if obj2 is an object with the same storage duration as the temporary t and created after the temporary t is created, t the temporary shall be destroyed after obj2 is destroyed. [ Example: ... ]
Change in 13.3.1.4 over.match.copy paragraph 1:
Change in 15.1 except.throw paragraphs 3 and 4:

Throwing an exception copy-initializes (8.5 dcl.init, 12.8 class.copy) a temporary an object, called the exception object. The storage for the exception object is allocated in an unspecified way, except as noted in 3.7.4.1 [basic.stc.dynamic.allocation]. The temporary is an lvalue and An lvalue designating the exception object is used to initialize the variable named in the matching handler (15.3 except.handle). If the ...

The memory for the exception object is allocated in an unspecified way, except as noted in 3.7.4.1 [basic.stc.dynamic.allocation]. If a handler exits by rethrowing, control is passed to another handler for the same exception. ...

Change in 17.6.4.9 res.on.arguments paragraph 1:
Change in 20.9.2.3.3 util.smartptr.weak.assign paragraph 2:
Remarks: The implementation may meet the effects (and the implied guarantees) via different means, without creating a temporary object.
Change in 26.6.2.1 emplate.valarray.overview paragraph 1:
... The illusion of higher dimensionality may be produced by the familiar idiom of computed indices, together with the powerful subsetting capabilities provided by the generalized subscript operators. [ Footnote: The intent is to specify an array template that has the minimum functionality necessary to address aliasing ambiguities and the proliferation of temporaries temporary objects. Thus, the valarray template is neither a matrix class nor a field class. However, it is a very useful building block for designing such classes. ]
Change in C.2.16 diff.cpp03.input.output: