Verständnis-Frage: Ressourcen-Freigabe bei unbehandelten Exceptions ?



  • Hi,
    wenn ich einer meiner Klassen eine Exception werfe, die der Benutzer meiner Klasse NICHT behandelt und folglich das Programm terminiert, werden die allokierten Resourcen (z.B. Speicher) vom Betriebsystem (Linux, Windows) wieder freigegeben ??

    Ich fürchte und vermute jetzt schon, die Antwort lautet NEIN... 😮 Um alles muss man sich selber kümmern ... oder doch nicht ??



  • Destruktoren werden bei dem Wurf einer Exception aufgerufen. Diese Tehnik verwendet man dann meist zur Freigabe von Ressourcen. Aus diesem Grund gibt es das Schlüsselwort finally in C++ auch nicht.



  • Wird Stack-Unwinding durchgeführt wenn die Exception ins Leere läuft?

    Wie dem auch sei: Zum Programmende werden alle Ressourcen des Betriebssystems auch von selbigem wieder eingesammelt. So richtige Speicherlecks sind Relikte aus Realmode- und 16bit-Zeiten. Nichtsdestotrotz sollte man sich natürlich selbst um seine Brocken kümmern, allein schon wenn das Programm länger laufen soll.

    Aber selbst gegen nicht gefangene Exceptions gibt es ein Mittel: Einfach angewöhnen in main immer ein try { } catch (...) { } um das Programm zu setzen 😉



  • Danke für die Info, geht's aber etwas präziser ? Heisst das, wenn eine Exception nicht behandelt wird und das Programm aus diesem Grund terminiert, werden Destruktoren aller Variablen aller Funktionen, die sich im Stack befinden, der Reihe nach aufgerufen ??



  • Ja, Destruktoren werden von allen automatischen Variablen aufgerufen. Wenn du allerdings mit new Objekte auf dem Heap allokiert hast, wird dafür nicht automatisch delete aufgerufen - für sowas gibts auto_ptr und die Boost-smartpointer



  • Um die (z.B. mit new auf dem Heap) selbst allokierten Resourcen kümmern sich klarerweise meine Destruktoren. Ich wollte nur sichergehen, ob sie denn im Fallen von unbehandelter Exception auch wirklich zum Zug kommen... Vielen Dank für die Antworten, wieder was gelernt 🙂



  • Das trifft alles auf C++ Exceptions zu, bei SEH (z.B. wegen einer Access Violation) werden keine Destruktoren aufgerufen. Das OS gibt aber die beanspruchten Ressourcen frei.



  • LordJaxom schrieb:

    Wird Stack-Unwinding durchgeführt wenn die Exception ins Leere läuft?

    Soweit ich weiß ist das undefiniert. EDIT: Implementation defined, siehe 15.5.1.

    Wie dem auch sei: Zum Programmende werden alle Ressourcen des Betriebssystems auch von selbigem wieder eingesammelt. So richtige Speicherlecks sind Relikte aus Realmode- und 16bit-Zeiten. Nichtsdestotrotz sollte man sich natürlich selbst um seine Brocken kümmern, allein schon wenn das Programm länger laufen soll.

    Es gibt natürlich auch Ressourcen, die nicht automatisch freigegeben werden. Lockfiles zum Beispiel.



  • Bashar schrieb:

    LordJaxom schrieb:

    Wird Stack-Unwinding durchgeführt wenn die Exception ins Leere läuft?

    Soweit ich weiß ist das undefiniert. EDIT: Implementation defined, siehe 15.5.1.
    ...

    Ich habe das vor einiger Zeit mal ausprobiert (mit gcc und VS6.0) ... und bei beiden wurde bei nichtgefangenen Exceptions KEIN Stack-unwindung gemacht. Damals hatte jemand (camper ? auf jedenfall jemand "Gewichtiges") auch erzählt, es sei eigentlich auch sinnvoller, weil man nach einem terminate() gerne noch anhand des Stacktraces den Programmzustand ermitteln würde - was nicht mehr (so einfach ?) ginge, wenn zuvor ein Stackunwindung gelaufen sei.
    Fand ich jedenfalls plausibel.

    Gruß,

    Simon2.



  • Bei mir (g++ 4.2.1) werden lokale Objekte nicht zerstört, bzw deren Destruktoren nicht aufgerufen, wenn ich eine Exception werfe... Außer ich fange sie irgendwo auf.



  • Wenn eine Exception nicht gefangen wird wird laut Standard IIRC terminate() aufgerufen, welches das Programm dann abbricht. Ob Stack Unwinding passiert oder nicht ist "implementation defined", kann sich also jede Implementierung frei aussuchen.

    Leider also nix worauf man sich verlassen kann.
    Das einzige was man also erzwingen kann ist dass immer Stack-Unwinding passiert, nämlich indem man selbst irgendwo ein catch(...) um das ganze Programm rum macht, dann hat man das Verhalten garantiert:

    int main()
    {
        try
        {
            return main2();
        }
        catch (...)
        {
            // stack unwinding ist hier bereits passiert
            terminate(); // oder exit(1) oder sowas
        }
    }
    


  • hustbaer schrieb:

    ...Ob Stack Unwinding passiert oder nicht ist "implementation defined", kann sich also jede Implementierung frei aussuchen.

    Leider also nix worauf man sich verlassen kann....

    Das wollte ich auch nicht behaupten ... nur eben, dass es auch Implementationen gibt, die KEINES machen (und dass es evtl. ganz sinnvoll sein kann).

    Gruß,

    Simon2.



  • Ich wollte die auch nicht zurechtweisen/korrigieren, sondern nur klarstellen dass das von dir beobachtete Verhalten im Standard ganz eindeutig "erlaubt" ist, und man sich daher auf nichts verlassen darf - nichtmal wenn man eine 100% konforme Implementierung hat (bzw. hätte, gibt ja keine) 🙂


Anmelden zum Antworten