CWG 1815 спросила (с небольшими изменениями):
struct A {}; struct B { A&& a = A{}; }; B b1; // #1 B b2{A{}}; // #2 B b3{}; // #3
[...]
#2
- это агрегированная инициализация, которая связываетB::a
с временным параметром в инициализаторе дляb2
и, таким образом, продлевает его время жизни до времениb2
.#3
- это агрегированная инициализация, но неясно, должно ли время жизни временного элемента в инициализаторе нестатических элементов данных дляB::a
продлеваться, как#2
, или нет, как#1
.
Согласно примечаниям по этой проблеме, на Issaquah (2014-02) CWG намеревалась заставить #3
вести себя как #2
; то есть правильно сформированный и продлевающий время жизни временного объекта, к которому привязан b3.a
. Но на следующем заседании ISO (Рапперсвиль, 2014-06) резолюция CWG 1696 была принята, якобы разрешив CWG 1815, но приняв что , похоже, делает #3
неверно сформированным:
11 - Временное выражение, привязанное к ссылочному элементу из инициализатора элемента по умолчанию, имеет неправильный формат.
Однако пример непосредственно под этим пунктом не рассматривает агрегатную инициализацию (как в CWG 1815), а только инициализацию конструктором; в частности, конструктор по умолчанию, определенный как заданный по умолчанию:
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
Таким образом, хотя формулировка кажется ясной, она также может показаться противоречащей намерению Комитета, что может быть основанием для того, чтобы считать формулировку дефектной.
Что касается практики реализации, мы можем увидеть, что существуют значительные расхождения:
gcc | clang | MSVC | ICC | |
---|---|---|---|---|
#1 |
❌ destroy | ✅ reject | ☠️ leak | ❌ destroy |
#2 |
✅ extend | ✅ extend | ✅ extend | ✅ extend |
#3 |
❌ extend | ❌ extend | ❌ extend | ❌ destroy |
(Здесь уничтожить означает, что временный объект уничтожен в конце объявления, т.е. не продлен срок службы. ✅ указывает на соответствие, ❌ несоответствие, ☠️ явный дефект.) Однако, кроме ICC, компиляторы соглашаются продлить время жизни в #3
, вопреки нынешней формулировке. Как ни странно, несмотря на продление срока службы, Clang предупреждает, что сделать это не может, указывая на то, что разработчики считают продление срока службы необходимым стандартом в этом случае:
предупреждение: извините, продление срока службы временного объекта, созданного совокупной инициализацией с использованием инициализатора члена по умолчанию, не поддерживается; время жизни временного закончится в конце полного выражения [-Wdangling]
Вопрос
Учитывая выраженное намерение CWG и вариативность реализации, разумно ли считать текущую формулировку дефектной и полагаться на продление срока службы, имеющееся в #3
? Знает ли Комитет об этом несоответствии и есть ли перспектива его устранения в ближайшей или среднесрочной перспективе (например, как DR на C ++ 20)?