Как я могу определить, активно ли исключение во время деструктора?

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

Я спрашиваю, потому что я хотел бы добавить некоторый код отладки, который объясняет, почему может возникать определенная ситуация и происходит ли это из-за исключений или нет.

4 ответа

Решение

std::uncaught_exception говорит вам, что стек разматывается из-за создаваемого исключения, о чем вы и просили.

Тем не менее, он не говорит вам, что вы, вероятно, хотите знать: находится ли объект, от деструктора которого вы его вызываете, в той части стека, которая разматывается, или в части стека, которая обычно уничтожается из-за Исключительно выход из области действия под другим деструктором, который является частью раскрутки:

struct A {
    ~A();
};

struct B {
    ~B();
}

int main() {
    try {
        A a;
        throw 1;
    } catch(...) {}
}

A::~A() {
    std::uncaught_exception(); // true
    B b;
}

B::~B() {
    std::uncaught_exception(); // also true, but "b" isn't being "unwound",
      // because ~A() returned, it didn't throw.
}

Вопреки словам DeadMG и Xeo, вы не можете получить ссылку на исключение, которое не было обнаружено. throw без операнда сбрасывает "текущее обработанное исключение", то есть исключение, в обработчике которого вы находитесь или чей-обработчик вызвал вас. Это не отбрасывает неисследованное исключение.

А как насчет нового C++17 std::uncaught_exceptions()? Я думаю, что вы можете создать код, который выглядит следующим образом:

class ExceptionSentinel
{
    int prev_uncaught;

public:
    ExceptionSentinel() : prev_uncaught(std::uncaught_exceptions()) {}

    ~ExceptionSentinel()
    {
        int cur_uncaught = std::uncaught_exceptions();
        if (cur_uncaught > prev_uncaught)
        {
            // ... ExceptionSentinel is being destructed by an stack unwinding process
        }
        else
        {
            // ... Normal destruction of ExceptionSentinel
        }
    }
};

В этом случае, std::uncaught_exceptions() отслеживает число необработанных исключений к моменту вызова кода. Больше информации можно найти на странице cppreference.

E сть std::uncaught_exception() функция. Однако, единственная полезная вещь, которую вы можете сделать, чтобы попытаться получить доступ к объекту исключения, - это сбросить его и попытаться его поймать. Вы никогда не должны бросать исключения из любого деструктора, в общем.

В C++, как я могу обнаружить в теле моего деструктора, разворачивается ли стек из-за исключения?

Не.

Могу ли я получить ссылку на активное исключение после обнаружения?

Нет.

Другие вопросы по тегам