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

Если инициализация или уничтожение прекращаются с помощью исключения, которое не обрабатывается, полностью уничтожены полностью построенные подобъекты?

В стандарте проводится различие между двумя формами уничтожения, которые возникают при возникновении исключения. Акцент на мой.

§15.2/1

Поскольку управление переходит из выражения throw в обработчик, деструкторы вызывают для всех автоматических объектов построенный с момента ввода блока try. Автоматические объекты уничтожаются в обратном порядке завершение их строительства.

§15.2/2

Объект любой продолжительности хранения, инициализация или уничтожение которого заканчивается исключением, будет имеют деструкторы, выполняемые для всех своих полностью построенных подобъектов (исключая варианты элементов класс объединения), т.е. для подобъектов, для которых главный конструктор (12.6.2) завершил выполнение и деструктор еще не приступил к исполнению. Аналогично, если конструктор без делегирования для объекта завершил выполнение, и конструктор делегирования для этого объекта завершает исключение, объекты  деструктор будет вызван. Если объект был выделен в новом выражении, соответствующее освобождение функция (3.7.4.2, 5.3.4, 12.5), если она есть, вызывается для освобождения памяти, занимаемой объектом.

§15.2/3

Процесс вызова деструкторов для автоматических объектов, построенных по пути от блока try к throw-expression называется "разворачивание стека". Если деструктор, вызванный во время разматывания стека, выходит с    исключение, std::terminate называется (15.5.1). [Примечание: деструкторы, как правило, поймают исключения и   не позволяйте им распространяться из деструктора. - конечная нота]

Итак, кажется, что мы имеем (a) раскрутку стека, которая разрушает автоматические объекты, и (b) уничтожение полностью построенных подобъектов объекта, конструктор или деструктор которого выходит из исключения, что происходит независимо от продолжительности хранения.

В осторожном чтении в § 15.2/1 предполагается, что разворачивание стека обязательно обязательно происходит, если управление переходит к обработчику, оставляя открытым возможность того, что удаление строк может не произойти, если исключение не обрабатывается. Действительно, в §15.5.2/2 говорится:

В ситуации, когда никакой обработчик соответствия не найден, он определяется реализацией независимо от того, разрывается ли стек до того, как вызывается std::terminate().

Но формулировка § 15.2/2, похоже, не оставляет открытой такой возможности. Он просто говорит, что инициализация или уничтожение должны быть прекращены за счет исключения - не то, что контроль должен пройти к обработчику. Поэтому моя интерпретация заключается в том, что даже если исключение не обрабатывается, подобъекты все еще уничтожаются. Это правильная интерпретация?

Например, допустим, что

std::vector<int> V;
ComplicatedObject* p = new ComplicatedObject();

и ComplicatedObject вызывает конструктор, и исключение не обрабатывается. Затем уничтожается ли V, определяется ли реализация. Является ли также определением реализации, уничтожены ли полностью построенные подобъекты *p? Обратите внимание, что такие объекты не имеют автоматической продолжительности хранения.

4b9b3361

Ответ 1

Ваша интерпретация (очевидно) правильная, и ни Кланг, ни GCC не соответствуют стандарту в этом сценарии.
Это было предметом Проблема CWG № 1774:

Текущая формулировка пункта 15.5.1 [except.terminate], пункт 2, дает реализации значительной степени свободы при исключении обработка результатов при вызове std::terminate:

В ситуации, когда соответствующий обработчик не найден [..]

Это контрастирует с обработкой подобъектов и объектов построенный посредством делегирования конструктов в пункте 15.2 [except.ctor] 2:

Объект любой продолжительности хранения [..]

Здесь должны быть вызваны деструкторы. Было бы полезно, если бы эти требования были согласованы.

Было предложено разрешение, которое не попало в С++ 14. Ваша цитата, §15.3/11, будет удалена. Вместо этого в §15.2 будет содержаться

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

Это должно устранить любые сомнения. Также обратите внимание, что изменения уже включены в текущий рабочий проект, N4296.

Ответ 2

Я реализовал обработку исключений и должен был прочитать код обработки исключений GCC. Я не совсем уверен, что стандарт гарантирует, но я знаю, что здесь происходит. В GCC, если исключение не обрабатывается, не будет выполняться раскрутка стека. Определение ABI для разворачивания стека в Unix-подобных системах просто заканчивает программу, если не вызывается обработчик. Он не разматывает кадры стека.

Аспект реализации, определенный в стандарте, позволяет оптимизировать. Возможно, вызваны некоторые деструкторы, поскольку они никогда не существовали в кадре стека времени выполнения. Оптимизатор переработал код и удалил некоторую обработку исключений. Таким образом, вы можете уничтожить некоторые объекты С++. Сумма будет минимальной, хотя в нижней части стека.

Ответ 3

Как вы указали:

Процесс вызова деструкторов для автоматических объектов, построенных по пути от блока try к выражению throw, называется "разматывание стека".

Это включает как объекты, так и "подобъекты" (которые являются просто автоматическими объектами, заключенными в другие объекты). Таким образом, уничтожение подобъектов является частью разворачивания стека, поскольку подобъекты на самом деле являются "автоматическими объектами, построенными по пути от блока try к throw-expression".

Итак, моя интерпретация заключается в том, что даже если исключение не обрабатывается, подобъекты все еще уничтожаются.

Субобъекты будут уничтожены, если реализация решит так, как описано в §15.5.2/2 (что вы также указали).


Является ли также определением реализации, уничтожены ли полностью построенные подобъекты * p?

Нет, потому что они попадают в набор подобъектов, что стандартные гарантии будут уничтожены в §15.2/2.