This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 115e. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2024-11-11


2669. Lifetime extension for aggregate initialization

Section: 11.9.3  [class.base.init]     Status: open     Submitter: Ed Catmur     Date: 2022-12-18     Liaison: EWG

Issue 1815 presented a subset of the following examples:

  struct A {};
  struct B { A&& a = A{}; };
  B b1;          // #1, default-initialization
  B b2{A{}};     // #2, aggregate initialization
  B b3{};        // #3, aggregate initialization
  B b4 = B();    // #4, value-initialization
  B b5(A{});     // #5, aggregate initialized via parentheses (9.4.1 [dcl.init.general] bullet 16.6.2.2)
  struct C { int i; A&& a = A{}; };
  C c6(1);       // #6, aggregate initialized via parentheses
  A a7 = C(1).a; // #7, aggregate initialized via parentheses

Issue 1696 was adopted, ostensibly resolving issue 1815, but the wording changes in 11.9.3 [class.base.init] paragraph 11 affected only the behavior of constructors, not of aggregate initialization:

A temporary expression bound to a reference member from a default member initializer is ill-formed. [ Example:
  struct A {
    A() = default;          // OK
    A(int v) : v(v) { }     // OK
    const int& v = 42;      // OK
  };
  A a1;     // error: ill-formed binding of temporary to reference
  A a2(1);  // OK, unfortunately
-- end example]

There is considerable implementation variance: #1 is rejected by clang, but accepted by gcc and EDG (with early destruction of the temporary); #2 is uniformly accepted and the lifetime of the temporary is extended; #3 is uniformly accepted, but only gcc, clang, and MSVC extend the lifetime of the temporary, whereas EDG does not.

Note that 9.4.1 [dcl.init.general] paragraph 7 specifies that default-initialization of aggregates is as-if the initializer () is used:

To default-initialize an object of type T means:

Such treatment causes early destruction of temporaries per 6.7.7 [class.temporary] bullet 6.10:

The exceptions to this lifetime rule are:

CWG 2023-05-12

CWG is soliciting the design guidance of EWG to resolve this issue, in particular for examples #3 and #6. For each of the presented examples, the standard should say whether the use is well-formed or not and whether the lifetime of the temporary is extended. It is also conceivable to implicitly delete the constructor being invoked (if any).

CWG recommends to leave #3 as-is and to make #6 (and thus #7) ill-formed. The trigger is the use of a default member initializer for a reference member that causes binding a temporary to that reference.

Forwarded to EWG via cplusplus/papers#1511.