Почему деструктор не вызван исключением?
Я ожидал, что A::~A()
будет вызван в этой программе, но это не так:
#include <iostream>
struct A {
~A() { std::cout << "~A()" << std::endl; }
};
void f() {
A a;
throw "spam";
}
int main() { f(); }
Однако, если я изменю последнюю строку на
int main() try { f(); } catch (...) { throw; }
то A::~A()
вызывается.
Я компилирую с 32-разрядным 32-разрядным компилятором С++ для компилятора Microsoft (R) 14.00.50727.762 для 80x86 "из Visual Studio 2005. Командная строка cl /EHa my.cpp
.
Правильно ли работает компилятор? Что говорит стандарт по этому вопросу?
Ответы
Ответ 1
Деструктор не вызывается, потому что terminate() для необработанного исключения вызывается до того, как стек разматывается.
Конкретные детали того, что говорит спецификация С++, вне моего знания, но трассировка отладки с gdb и g++, похоже, подтверждает это.
В соответствии с черновик проекта в разделе 15.3 bullet 9:
9 If no matching handler is found in a program, the function terminate()
(_except.terminate_) is called. Whether or not the stack is unwound
before calling terminate() is implementation-defined.
Ответ 2
Спецификация языка С++:
Процесс вызова деструкторов для автоматических объектов, построенных по пути от блока try к throw-выражению, называется "разворачивание стека".
В исходном коде не содержится блок try, поэтому разворачивание стека не происходит.
Ответ 3
Во втором примере dtor вызывается, когда он покидает блок try {}.
В первом примере dtor вызывается, когда программа выключается после выхода из функции main() --- к тому времени cout может быть уже уничтожен.
Ответ 4
Я также предположил, что компилятор не генерирует код относительно "a", поскольку он не ссылается, но все же, это не правильное поведение, поскольку деструктор выполняет что-то, что необходимо выполнить.
Итак, я пробовал в VS2008/vc9 (+ SP1), Debug и Release и ~ A вызывается после того, как исключение выбрано, выйдя из f() - это правильное поведение, если я прав.
Теперь я просто попытался с VS2005/vc8 (+ SP1), и это то же поведение.
Я использовал точки останова, чтобы быть уверенным. Я только что проверил с консолью, и у меня тоже есть сообщение "~ A". Может быть, вы сделали это неправильно в другом месте?
Ответ 5
Этот вопрос легко для Google, поэтому я разделяю свою ситуацию здесь.
Удостоверьтесь, что yor exeption не пересекает границу extern "C"
или не использует параметр MSVC/EHs (Включить исключения С++ = Да с функциями Extern C (/EHs))
Ответ 6
Извините, у меня нет копии стандарта на меня.
Я определенно хотел бы дать окончательный ответ на этот вопрос, поэтому кто-то с копией стандарта захочет поделиться главой и стихом о том, что происходит:
Из моего понимания terminate вызывается только iff:
- Механизм обработки исключений не может найти обработчик для созданного исключения.
Ниже приводятся более конкретные случаи:
- Во время разматывания стека исключение выходит из деструктора.
- Заброшенное выражение, исключение исключает конструктор.
- Исключение исключает конструктор/деструктор не локального статического (то есть глобального)
- Исключение исключает функцию, зарегистрированную с помощью atexit().
- Исключение исключает main()
- Попытка повторного выброса исключения, когда в настоящее время не распространяется какое-либо исключение.
- Неожиданное исключение исключает функцию с помощью спецификаторов исключения (с помощью неожиданного)