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

Развертывание стека с исключениями, гарантируемыми стандартом С++?

Что касается разворачивания стека, в стандарте С++ говорится:

Исключение считается неотображенным после завершения инициализации объекта исключения ([except.throw]) до завершения активации обработчика исключения ([except.handle]). Это включает разматывание стека.

на par 15.5.3 текущего стандарта. Я пытался понять, к чему относится последнее предложение (This includes stack unwindings):

  • Предполагается, что компилятор должен позаботиться о разматывании стека?
  • или, если он говорит, что он зависит от компилятора, нужно ли разматывать или нет стек?

Вопрос возникает из следующего фрагмента:

#include <iostream>
#include <exception>

struct S{
    S() { std::cout << " S constructor" << std::endl; }
    virtual ~S() { std::cout << " S destructor" << std::endl; }
};

void f() {
    try{throw(0);}
    catch(...){}
}

void g() {
    throw(10);
}

int main() {
    S s;
    f();
    //g();
}

Теперь:

  • если вы запустили его как-есть (поймать исключение), у вас есть подсказка об отказе стека
  • если вы прокомментируете f(); и раскомментируете g(); (не перехватывая исключение), у вас есть намек на то, что стек не развязан

Итак, оба эксперимента, похоже, в пользу первой пули выше; как clang++, так и g++ соглашаются на результат (но это не дискриминант).

Кроме того, мне очень странно, что стандарт, который очень осторожен в определении времени и продолжительности объекта, оставляет здесь тень.

Может кто-нибудь уточнить? Развертывание стека для исключенных исключений, гарантированных стандартом? Если да, то где? Если нет, то почему?

4b9b3361

Ответ 1

Развертывание стека для исключенных исключений, гарантированных стандартом?

Непрерывность стека гарантируется только для исключенных исключений ([except.handle]/9):

Если соответствующий обработчик не найден, вызывается функция std::terminate(); независимо от того, разворачивается ли стек до того, как этот вызов std::terminate() будет реализован.

Таким образом, это определяется реализацией, в противном случае.

Если нет, почему?

В случае неперехваченного исключения стандарт вызывает std::terminate. Это означает завершение выполнения программы. Если у вас есть определенный способ регистрации информации о состоянии системы в определенный момент времени, вы можете не хотеть, чтобы это состояние было нарушено путем разворачивания стека.

И если вы этого не делаете... тогда вам все равно.

Если вам действительно нужно, чтобы стек всегда разматывался, вы можете поместить свой код main (и любые функции потока) в блок try {} catch(...) {throw;}.