Frage

Angenommen, ich habe eine Klasse wie folgt aus:

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

Es scheint, dass destructor ~Boda nie, so Ressource der ptr aufgerufen wird nie freigegeben erhalten.

Hier ist die Ausgabe des Programms:

terminate called after throwing an instance of 'int'
Aborted

So ist es die Antwort auf meine Frage scheint, ist No.

Aber ich dachte, dass der Stapel abgewickelt bekam, wenn eine Ausnahme ausgelöst wurde? Warum nicht Boda b Objekt hat in meinem Beispiel bekommen zerstört?

Bitte helfen Sie mir, diese Ressource Problem zu verstehen. Ich möchte eine bessere Programme in der Zukunft schreiben.

Auch ist dies die so genannten RAII?

Danke, Boda cyclo.

War es hilfreich?

Lösung

Wenn die Ausnahme nicht irgendwo gefangen ist, dann ist die C ++ Laufzeit ist frei gerade zu gehen, um das Programm beendet wird, ohne dass Stapel zu tun Abwickeln oder keine Destruktoren aufrufen.

Wenn Sie jedoch einen Try-Catch-Block um den Anruf zu bad() hinzufügen, werden Sie den destructor für das das Boda Objekt sehen aufgerufen wird:

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

RAII Mittel, die dynamisch (heap) zugewiesenen Speicher immer durch eine automatisch (stack) zugeordnet Objekt gehört, dass es, wenn die Speicherfreigabe-Objekt zerstört. Diese stützt sich auf die Garantie, dass die destructor, wenn der automatisch zugeordnet Objekt Spielraum erlischt aufgerufen wird, sei es durch eine normale Verzinsung oder aufgrund einer Ausnahme.

Diese Ecke-Fall Verhalten ist in der Regel kein Problem in Bezug auf RAII, da in der Regel der Hauptgrund, dass Sie die Destruktoren ausgeführt werden soll, um Speicher frei ist, und alle Speicher zurück in die OS gegeben, wenn Ihr Programm ohnehin beendet. Allerdings, wenn Ihr Destruktoren etwas mehr tun, kompliziert, wie vielleicht eine Lock-Datei auf der Festplatte oder etwas entfernen, wo es einen Unterschied machen würde, ob das Programm Destruktoren aufgerufen oder nicht, wenn abstürzt, können Sie Ihre main in einem Try-Catch-Block wickeln möchten, dass alles Fänge (nur bis Ausfahrt Ausnahme sowieso) nur um sicherzustellen, dass der Stapel abwickelt immer vor dem Abschluss.

Andere Tipps

Der Destruktor wird nicht ausgeführt werden, wenn eine Ausnahme im Konstruktor auftritt.

Es wird bei Bedarf ausgeführt werden (wenn Ausnahme irgendwo behandelt wird), wenn Ausnahme wie in Ihrem Beispiel in einem anderen Verfahren erhöht wird. Aber da das Programm beendet wird, ist die destructor Aufruf nicht notwendig, hier und Verhalten hängt von Compiler ...

Die Idee ist, dass RAII Konstruktor ordnet Ressourcen und destructor befreit sie. Wenn eine Ausnahme in Konstruktor auftritt, gibt es keine einfache Möglichkeit, wich Ressourcen zu wissen, wo zugeordnet und welche nicht (es hängt von der genauen Stelle im Konstruktor, wo Ausnahme aufgetreten). Sie sollten auch bedenken, dass, wenn ein Konstruktor fehlschlägt, ist der einzige Weg, es zu sagen, dass es den Anrufer, eine Ausnahme zu erhöhen und zugewiesenen Speicher freigegeben wird (entweder Stapel Abwickeln oder Heap-Speicher zugewiesen), als ob es nie waren zugeordnet.

Die Lösung liegt auf der Hand: Wenn eine Ausnahme in einem Konstruktor auftreten können, haben Sie es zu fangen und zugeordneten Ressourcen frei, wenn nötig. Es kann tatsächlich einige duplizierten Code mit destructor sein, aber das ist kein großes Problem.

In destructor sollten Sie keine Ausnahmen erhöhen, da es zu großen Problemen mit Stack Abwickeln führen kann.

In jedem anderen Verfahren, Verwendung Ausnahmen, wie Sie wollen, aber vergessen Sie nicht, sie irgendwo zu behandeln. Eine nicht behandelte excception kann überhaupt als keine Ausnahme schlimmer sein. Ich kenne einige Programme, die ... und für Fehler nicht abstürzt Ausnahmen für einige kleinere Fehler behandeln, die eine Warnung nur herausgeben sollte.

Versuchen Sie, den Strom Spülung - Sie werden sehen, dass der Destruktor in der Tat genannt wird:

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

Es ist die Pufferung des I / O, dass Verzögerungen der Ausdruck bis zu dem Punkt, dass Programmabbruch Kürzungen vor der eigentlichen Ausgabe.

Edit:

Die obige gilt für behandelt Ausnahmen . Mit nicht behandelte Ausnahmen der Standard spezifiziert nicht, ob Stapel abgewickelt werden oder nicht. Siehe auch diese Frage SO .

scroll top