问题
CWG 1815 asked (with minor edits):
struct A {}; struct B { A&& a = A{}; }; B b1; // #1 B b2{A{}}; // #2 B b3{}; // #3
[...]
#2
is aggregate initialization, which bindsB::a
to the temporary in the initializer forb2
and thus extends its lifetime to that ofb2
.#3
is aggregate initialization, but it is not clear whether the lifetime of the temporary in the non-static data member initializer forB::a
should be lifetime-extended like#2
or not, like#1
.
Per the Notes on that issue, at Issaquah (2014-02) CWG intended to make #3
behave like #2
; that is, well-formed, and performing lifetime extension of the temporary to which b3.a
binds. But at the next ISO meeting (Rapperswil, 2014-06) the resolution to CWG 1696 was adopted, ostensibly resolving CWG 1815 but adopting language that appears to make #3 ill-formed:
11 - A temporary expression bound to a reference member from a default member initializer is ill-formed.
However, the example immediately under that clause does not consider aggregate initialization (as in CWG 1815) but only initialization by constructor; specifically, a default constructor defined as defaulted:
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
So although the wording seems clear, it would also seem contrary to the intent of the Committee, which could be reason to consider the wording defective.
In terms of implementation practice, we can see that there is considerable variance:
gcc | clang | MSVC | ICC | |
---|---|---|---|---|
#1 |
❌ destroy | ✅ reject | ☠️ leak | ❌ destroy |
#2 |
✅ extend | ✅ extend | ✅ extend | ✅ extend |
#3 |
❌ extend | ❌ extend | ❌ extend | ❌ destroy |
(Here, "destroy" means the temporary is destructed at the end of the declaration i.e. not lifetime-extended. ✅ indicates conformance, ❌ non-conformance, ☠️ a clear defect.) However, other than ICC, the compilers agree on extending lifetime in #3
, contrary to the current wording. Oddly, despite performing lifetime extension, Clang warns that it is unable to do so, indicating that the developers consider lifetime extension to be required by the Standard in this case:
warning: sorry, lifetime extension of temporary created by aggregate initialization using default member initializer is not supported; lifetime of temporary will end at the end of the full-expression [-Wdangling]
Question
Given the expressed intent of CWG, and implementation variance, is it reasonable to consider the current wording as defective and to rely on lifetime extension occurring in #3
? Are the Committee aware of this discrepancy and is there prospect of it being resolved in the near or medium term (as a DR to C++20, say)?
来源:https://stackoverflow.com/questions/65528744/validity-and-or-lifetime-extension-of-mem-initializer-in-aggregate-initializatio