Подтвердить что ты не робот

Стандарт С++ гарантирует, что единообразная инициализация исключает безопасность?

#include <iostream>

using namespace std;

struct A
{
    A() { cout << "A" << endl; }
    ~A() { cout << "~A" << endl; }
};

A Ok() { return {}; }
A NotOk() { throw "NotOk"; }

struct B
{
    A a1;
    A a2;
};

void f(B) {}

int main()
{
    try
    {
        f({ Ok(), NotOk() });
    }
    catch (...)
    {}
}

vc++ и clang вывод:

A
~A

Пока gcc выводит:

A

Кажется серьезной ошибкой GCC.

Для справки см. ошибка GCC 66139 и "Серьезная ошибка в GCC" Анджей Кржемейски.

Мне просто интересно:

Означает ли стандарт С++, что единообразная инициализация является безопасной?

4b9b3361

Ответ 1

Кажется, так:

Любопытно найти в §6.6/2 Jump Statements [stmt.jump] всех мест (N4618):

При выходе из области действия (как бы это ни было выполнено) объекты с автоматическим (3.7.3), которые были построены в этой области, уничтожены в обратном порядке их строительства. [Примечание: для временные, см. 12.2. -end note] Передача из цикла из блок или назад после инициализированной переменной с автоматическим хранилищем длительность включает в себя уничтожение объектов с автоматическим хранением продолжительность, которая находится в сфере действия в точке, переданной, но не в точка передана. (См. 6.7 для передачи в блоки). [ Заметка: Тем не менее, программа может быть завершена (путем вызова std::exit() или std::abort() (18.5), например) без уничтожения объектов класса с автоматическим временем хранения. -end note]

Я думаю, что акцент здесь делается на "(хотя и достигнутой)" части. Это включает исключение (но исключает вещи, которые вызывают std::terminate).


ИЗМЕНИТЬ

Я думаю, что лучшая ссылка: §15.2/3 Конструкторы и деструкторы [except.ctor] (emphasis):

Если инициализация или уничтожение объекта, кроме делегирующий конструктор завершается исключением, деструктор вызывается для каждого из объектов прямых подобъектов, а для полный объект, подобъекты виртуального базового класса, инициализация которых (8.6) и деструктор которого еще не начался, за исключением того, что в случае уничтожения члены варианта союзный класс не уничтожаются. Субобъекты уничтожаются в обратный порядок завершения их строительства. такие разрушение секвенировано до ввода обработчика function-try-block конструктора или деструктора, если таковые имеются.

Это будет включать в себя агрегатную инициализацию (которую я узнал сегодня, можно назвать непустой инициализацией)

... и для объектов с конструкторами мы можем привести статью 12.6.2/12 [class.base.init] (emphasis):

В конструкторе без делегирования деструктор для каждого потенциально построенный подобъект типа класса потенциально вызывается (12.4). [ Примечание: Это условие гарантирует, что деструкторы могут быть вызваны для полностью построенные подобъекты в случае, если исключение выбрано (15.2). -end note]