Title
Lifetime extension of temporaries past function return
Status
open
Section
6.8.7 [class.temporary]
Submitter
Hubert Tong

Created on 2025-09-12.00:00:00 last changed 1 month ago

Messages

Date: 2025-09-14.07:41:08

Suggested resolution (Option 2):

  1. Move to before 6.8.2 [intro.object] paragraph 11 from 7.7 [expr.const] paragraph 2:

    The constituent values of an object o are
    • if o has scalar type, the value of o;
    • otherwise, the constituent values of any direct subobjects of o other than inactive union members.
    The constituent references of an object o are
    • any direct members of o that have reference type, and
    • the constituent references of any direct subobjects of o other than inactive union members.
    Some operations are described as implicitly creating objects ...
  2. Remove 7.7 [expr.const] paragraph 2 and change paragraph 3 as follows:

    The constituent values of an object o are
    • if o has scalar type, the value of o;
    • otherwise, the constituent values of any direct subobjects of o other than inactive union members.
    The constituent references of an object o are
    • any direct members of o that have reference type, and
    • the constituent references of any direct subobjects of o other than inactive union members.
    The constituent values and constituent references of a variable x are defined as follows:
    • If x declares an object, the constituent values and references of that object (6.8.2 [intro.object]) are constituent values and references of x.
    • If x declares a reference, that reference is a constituent reference of x.
    ...
  3. Add in 8.8.4 [stmt.return] paragraph 6 as follows:

    In a function whose return type is a reference, other than an invented function for std::is_convertible (21.3.8 [meta.rel]), a return statement that binds
    • the a returned reference or
    • a constituent reference (6.8.2 [intro.object]) of a returned object
    to a temporary expression (6.8.7 [class.temporary]) is ill-formed. [ Example: ... ]
Date: 2025-09-14.07:41:08

Suggested resolution (Option 1):

Add in 6.8.7 [class.temporary] bullet 6.11 as follows:

  • ...
  • A temporary object bound to a reference element of an aggregate of class type initialized from a parenthesized expression-list (9.5 [dcl.init]) persists until the completion of the full-expression containing the expression-list.
  • The lifetime of a temporary bound to a constituent reference (7.7 [expr.const]) of the returned object in a function return statement (8.8.4 [stmt.return]) is not extended; the temporary is destroyed at the end of the full-expression in the return statement.
  • A temporary bound to a reference in a new-initializer (7.6.2.8 [expr.new]) persists until ...
Date: 2025-10-10.06:36:14
N5028 comment CA 040

(From submission #760.)

Consider:

  struct B { ~B(); };
  struct A { const B &b; };
  A foo() { return {{}}; }   // #1
  void bar();
  int main() {
    A a = foo();
    bar();
  }

At #1, a temporary of type B is created and, due to guaranteed copy elision, is bound to a.b in main. The current rules, as amended by P2748R5 (Disallow Binding a Returned Glvalue to a Temporary), prescribe lifetime extension of that temporary, which is a novel requirement accidentally imposed by P2748R5 that is hard to implement.

History
Date User Action Args
2025-09-14 07:41:08adminsetmessages: + msg8106
2025-09-12 22:42:26adminsetmessages: + msg8096
2025-09-12 00:00:00admincreate