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

Исключение в Destructor С++

Мне хорошо известно, что в деструкторе нельзя исключать какие-либо исключения.

Но, как часть моего понимания этой концепции, я закодировал этот пример: -

#include <iostream>
using namespace std;

class A {
private: 
    int i;

public:
    A()
    {
        i = 10;
    }
    ~A()
    {
        throw 30;
    }
};
int main(){
    try{
        A();
        throw 10;
    }
    catch (int i){
        cout << i << endl;
        cout << "exception caught" << endl;
    }
}

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

30
exception caught

Может кто-нибудь объяснить мне логику этого, почему это не заканчивается?

4b9b3361

Ответ 1

std::terminate будет вызываться, если исключение генерируется во время разматывания стека. Это означает, что если вызывается исключение, когда обрабатывается другое исключение, тогда будет вызываться std::terminate.

В вашем примере этого не произойдет - A(); построит и немедленно уничтожит экземпляр A. Затем throw 30 будет правильно поймано.

Изменение кода на:

int main(){
    try{
        A a;      // begin `a` lifetime 
        throw 10; // | throw #0           
                  // | end `a` lifetime   
                  // throw #1
    }
    catch(int i){
        cout<<i<<endl;
        cout<<"exception caught"<<endl;
    }
}

гарантирует, что будет вызываться std::terminate. В этом случае A будет уничтожен и будет бросать , пока обрабатывается другое исключение.

пример live coliru


Дополнительная информация:


Обратите внимание, что в С++ 11 и выше, ваш фрагмент кода вызовет std::terminate и предоставит вам предупреждение:

main.cpp: В деструкторе 'A:: ~ A():

main.cpp: 16: 15: предупреждение: throw всегда будет вызывать terminate() [-Wterminate]

     throw 30;

           ^~

main.cpp: 16: 15: примечание: в дескрипторах С++ 11 по умолчанию noexcept

завершение вызова после вызова экземпляра 'int'

bash: строка 7: 1505 Отменено (ядро сбрасывается)./a.out

Как видно из вывода компилятора, поскольку С++ 11 деструкторы неявно noexcept(true). Если вы хотите предотвратить это поведение, вы можете просто отметить их как noexcept(false). Пример:

~A() noexcept(false)
{
    throw 30;
}

живой пример на coliru

Ответ 2

В вашем примере A() создайте временную переменную для A, а затем уничтожьте ее немедленно. Таким образом, throw 10; никогда не выполняется.

Заявление throw выполняется в деструкторе для A. При выполнении A::~A() программа не разматывается (т.е. Очищает состояние от исключения) в этой точке. См. "Деструкторы, которые бросают" , например.