web-dev-qa-db-fra.com

Exception dans Destructor C ++

Je suis bien conscient du fait qu'il ne faut pas lancer d'exception dans le destructeur.

Mais dans le cadre de ma prise en main sur ce concept, j'ai codé cet exemple: -

#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;
    }
}

Selon ma compréhension, ce programme devrait être terminé en appelant std :: terminate () car il y aura deux exceptions en même temps. Mais, ce programme donne la sortie suivante: -

30
exception caught

Quelqu'un peut-il s'il vous plaît m'expliquer la logique derrière cela pour expliquer pourquoi cela ne se termine pas?

35
amit singh

std::terminate Sera appelé si une exception est levée pendant le déroulement de la pile . Cela signifie que si une exception est appelée tandis qu'une autre exception est gérée, alors std::terminate Sera appelé.

Dans votre exemple, cela ne se produit pas - A(); construira et détruira immédiatement une instance de A. Le throw 30 Sera alors correctement capturé.

Changer votre code pour:

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;
    }
}

garantira que std::terminate sera appelé. Dans ce cas, a sera détruit et lancera pendant qu'une autre exception est gérée .

exemple de coliru en direct


Information additionnelle:


Notez que en C++ 11 et supérieur , votre extrait de code appellera std::terminate Et vous avertira:

main.cpp: Dans le destructeur ‘A :: ~ A ()’:

main.cpp: 16: 15: avertissement: throw appellera toujours terminate () [-Wterminate]

     throw 30;

           ^~

main.cpp: 16: 15: note: dans les destructeurs C++ 11 par défaut à noexcept

terminate appelé après avoir lancé une instance de 'int'

bash: ligne 7: 1505 abandonné (core dumpé) ./a.out

Comme on le voit dans la sortie du compilateur, puisque les destructeurs C++ 11 sont implicitement noexcept(true). Si vous souhaitez empêcher ce comportement, vous pouvez simplement les marquer comme noexcept(false). Exemple:

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

exemple en direct sur coliru

62
Vittorio Romeo

Dans votre exemple, A() construit une variable temporaire pour A puis la détruit immédiatement. Ainsi throw 10; N'est jamais exécuté.

L'instruction throw en cours d'exécution se trouve dans le destructeur de A. Lors de l'exécution de A::~A(), le programme ne se déroule pas (c'est-à-dire nettoie l'état d'une exception) à ce stade. Voir "Destructeurs qui lancent" par exemple.

10
EyasSH