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

Почему деструктор не вызван исключением?

Я ожидал, что 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.

Правильно ли работает компилятор? Что говорит стандарт по этому вопросу?

4b9b3361

Ответ 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()
  • Попытка повторного выброса исключения, когда в настоящее время не распространяется какое-либо исключение.
  • Неожиданное исключение исключает функцию с помощью спецификаторов исключения (с помощью неожиданного)