Question

Supposons que j'ai une classe comme ceci:

#include <iostream>

using namespace std;

class Boda {
    private:
        char *ptr;

    public:
        Boda() {
            ptr = new char [20];
        }
        ~Boda() {
            cout << "calling ~Boda\n";

            delete [] ptr;
        }

        void ouch() {
            throw 99;
        }
};

void bad() {
    Boda b;
    b.ouch();
}

int main() {
    bad();
}

Il semble que ~Boda destructor ne sera jamais appelé, donc la ressource ptr jamais se libérer.

Voici la sortie du programme:

terminate called after throwing an instance of 'int'
Aborted

Il semble donc la réponse à ma question est No.

Mais je pensais que la pile a dévidé lorsqu'une exception se est jeté? Pourquoi ne pas l'objet Boda b se destructed dans mon exemple?

S'il vous plaît me aider à comprendre ce problème de ressources. Je veux écrire de meilleurs programmes à l'avenir.

Aussi, est-ce que l'on appelle RAII?

Merci, Boda Cydo.

Était-ce utile?

La solution

Si l'exception n'est pas pris partout, l'environnement d'exécution C ++ est libre d'aller directement à terminer le programme sans faire une pile de déroulement ou d'appeler des Destructeurs.

Cependant, si vous ajoutez un bloc try-catch autour de l'appel à bad(), vous verrez le destructor pour le l'objet Boda appelé:

int main() {
    try {
      bad();
    } catch(...) {  // Catch any exception, forcing stack unwinding always
      return -1;
    }
}

RAII signifie que dynamiquement (tas) mémoire allouée est toujours appartenant à un automatiquement (stack) de l'objet alloué qui Libère lorsque le destructs d'objet. Cela repose sur la garantie que le destructor sera appelée lorsque l'objet automatiquement alloué est hors de portée, que ce soit en raison d'un rendement normal ou en raison d'une exception.

Ce comportement coin cas est normalement pas un problème en ce qui concerne RAII, puisque généralement la principale raison pour laquelle vous voulez que les Destructeurs à terme est de libérer de la mémoire, et toute la mémoire est rendu au système d'exploitation lorsque votre programme se termine de toute façon. Toutefois, si votre Destructeurs faire quelque chose de plus compliqué, comme enlever peut-être un fichier de verrouillage sur le disque ou quelque chose, où il ferait une différence si le programme appelé Destructeurs ou non lors d'un plantage, vous pouvez envelopper votre main dans un bloc try-catch qui prises tout (seulement pour sortir en cas d'exception de toute façon), juste pour faire en sorte que la pile dévide toujours avant de se terminer.

Autres conseils

Le destructor ne sera pas exécutée si une exception se produit dans le constructeur.

Il sera exécuté si nécessaire (si exception est gérée quelque part) si exception est soulevée dans une autre méthode comme dans votre exemple. Mais le programme est terminé, appelant le destructor n'est pas nécessaire ici et le comportement dépend du compilateur ...

L'idée de RAII est que constructeur et alloue ressources Libère destructor eux. Si une exception se produit dans le constructeur, il n'y a aucun moyen simple de savoir où Wich ressources allouées et qui ne sont pas (cela dépend de l'endroit exact où dans le constructeur exception se est produite). Rappelez-vous aussi que si un constructeur échoue, la seule façon de le dire à l'appelant à soulever une exception et mémoire allouée est libérée (soit déroulage pile ou la mémoire allouée tas) comme si elle était jamais alloué.

La solution est évidente: si une exception peut se produire dans un constructeur, vous devez l'attraper et libérer ressources allouées si nécessaire. Il peut effectivement être un code avec dupliquée destructor, mais ce n'est pas un gros problème.

Dans destructor vous ne devriez pas soulever des exceptions, car il peut conduire à de gros problèmes avec le déroulement pile.

Dans une autre méthode, les exceptions d'utilisation que vous le souhaitez, mais ne pas oublier de les manipuler quelque part. Une excception non gérée peut être pire que pas une exception du tout. Je sais que certains programmes qui ne gère pas des exceptions pour certaines erreurs mineures ... et Crash d'erreurs qui ne devrait émettre un avertissement.

Essayez le rinçage du flux - vous verrez que le destructor est en effet appelé:

cout << "calling ~Boda" << endl;

Il est la mise en mémoire tampon des E / S que les retards de l'impression au point que les réductions de terminaison du programme en avant la sortie réelle.

Edit:

Les cales ci-dessus pour exceptions traitées . Avec exceptions non gérées la norme ne spécifie pas si la pile est dévidé ou non. Voir aussi cette question SO .

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top