This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 119a. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.
2025-12-20
[Voted into WP at March 2004 meeting.]
class C {public: C(); ~C(); int& get() { return p; } // reference returnprivate: int p;};int main (){ if ( C().get() ) // OK?}Section 6.8.7 [class.temporary] paragraph 3 says a temp isdestroyed as the last step inevaluating the full expression. But the expression C().get() has areference type. Does 6.8.7 [class.temporary] paragraph 3 requirethat the dereference to get aboolean result occur before the destructor runs, making the codevalid? Or does the code have undefined behavior?
Bill Gibbons:It has undefined behavior, though clearly this wasn't intended.The lvalue-to-rvalue conversion that occurs in the "if" statement isnot currently part of the full-expression.
From section 6.8.7 [class.temporary] paragraph 3:
Temporary objects are destroyed as the last step in evaluating the full-expression (6.10.1 [intro.execution])that (lexically) contains the point where they were created.
From section 6.10.1 [intro.execution] paragraph 12:
A full-expression is an expression that is not a subexpression of another expression. If a language construct is defined to produce an implicit call of a function, a use of the language construct is considered to be an expression for the purposes of this definition.
The note in section 6.10.1 [intro.execution] paragraph 12 goeson to explain that this coversexpressions used as initializers, but it does not discusslvalues within temporaries.
It is a small point but it is probably worth correcting6.10.1 [intro.execution] paragraph 12.Instead of the "implicit call of a function" wording, it mightbe better to just say that a full-expression includes any implicituse of the expression value in the enclosing language construct,and include a note giving implicit calls and lvalue-to-rvalueconversions as examples.
Offhand the places where this matters include: initialization (including member initializers), selection statements, iteration statements, return, throw
Proposed resolution (April 2003):
Change 6.10.1 [intro.execution] paragraph 12-13 to read:
Afull-expression is an expression that is not asubexpression of another expression. If a language construct isdefined to produce an implicit call of a function, a use of thelanguage construct is considered to be an expression for thepurposes of this definition.Conversions applied to the result ofan expression in order to satisfy the requirements of the languageconstruct in which the expression appears are also considered to bepart of the full-expression.
[Note: certain contexts in C++ cause the evaluationof a full-expression that results from a syntactic construct otherthanexpression (7.6.20 [expr.comma]). For example,in 9.5 [dcl.init] one syntax forinitializer is[Example:
(expression-list )but the resulting construct is a function call upon a constructorfunction withexpression-list as an argument list; such afunction call is a full-expression. For example, in9.5 [dcl.init], anothersyntax forinitializer isbut again the resulting construct might be a function call upon aconstructor function with oneassignment-expression as anargument; again, the function call is a full-expression. ]
=initializer-clausestruct S { S(int i): I(i) { } int& v() { return I; } private: int I; }; S s1(1); //full-expression is call of S::S(int) S s2 = 2; //full-expression is call of S::S(int) void f() { if (S(3).v()) //full-expression includes lvalue-to-rvalue and // int to bool conversions, performed before //temporary is deleted at end of full-expression { } }—end example]