Ich habe den folgenden Code geschrieben, der die Operatoren new
und delete
überlädt und eine Exception im Destruktor auslöst.
Wenn die Ausnahme ausgelöst wird, warum wird der Code im Operator delete
nicht ausgeführt (und "tschüss" gedruckt)?
Wenn es nicht ausgeführt werden soll, (wie) wird der Speicher freigegeben? Wird einer der anderen delete
-Operatoren aufgerufen? Würde eine Überladung stattdessen dazu führen, dass der entsprechende Code ausgeführt wird? Oder ist die Erinnerung einfach nicht befreit, weil eine fehlgeschlagene Zerstörung impliziert, dass es vielleicht nicht sein sollte?
Ausgabe:
%Vor%Ich schaute auf:
Aber ich konnte keine Antwort darauf finden, was genau passiert (1) für eine Ausnahme im Destruktor (im Gegensatz zum Konstruktor) und (2) mit einem überladenen Löschen.
Ich brauche keine Vorlesung darüber, eine Ausnahme in einem Destruktor zu werfen, was eine schlechte Übung ist - ich bin einfach auf ähnlichen Code gestoßen und ich bin neugierig auf das Verhalten.
Ich würde eine Antwort vorziehen, die durch den Standard oder ähnliche Referenzen unterstützt wird, wenn solche Referenzen existieren.
Die Standardentwurf N4296 5.3.5, S. 121 sagt:
[expr.delete] [Hinweis: Die Freigabe-Funktion wird unabhängig davon aufgerufen, ob der Destruktor für das Objekt oder ein Element des Arrays eine Ausnahme auslöst. - Endnote]
Also muss die operator delete
regardless genannt werden, die der Destruktor wirft.
Wie jedoch aus den Kommentaren hervorgeht, ruft einige Compiler das operator delete
nicht richtig auf. Dies kann als Fehler-Compiler gelöst werden.
Bug getestet für:
In der C ++ - Norm von 1998 (ISO / IEC 14882 Erste Ausgabe, 1998-09-01) wird die Funktionsweise eines Löschausdrucks ganz einfach in "Abschnitt 5.3.5 Löschen [expr.delete]" in den Absätzen 6 und 7 angegeben .
6 Der delete-expression ruft den Destruktor (falls vorhanden) für das Objekt oder die Elemente des Arrays auf, die gelöscht werden sollen. Im Fall eines Arrays werden die Elemente in der Reihenfolge der abnehmenden Adresse (d. H. In umgekehrte Reihenfolge der Fertigstellung ihres Konstruktors; siehe 12.6.2).
7 Der delete-expression ruft eine Freigabe-Funktion (3.7.3.2) auf.
In Kombination erfordern diese Klauseln, dass der Destruktor aufgerufen wird (oder Destruktoren für ein Array) und dass die Freigabe-Funktion bedingungslos aufgerufen wird. Es gibt keine Vorkehrung dafür, die Deallokationsfunktion nicht aufzurufen, wenn eine Ausnahme ausgelöst wird.
Im Sprachstandard von 1998 werden sich Sprachanwälte und Compilerentwickler wahrscheinlich über die Sophistik freuen, eine andere Interpretation als die oben genannten zu argumentieren. Glücklicherweise sind die Dinge in späteren Standards expliziter ...
In Entwurf N4296 verfügbar unter open-std.org dieselben Klauseln werden wie folgt erweitert: (aus dem Gedächtnis ist der Wortlaut im offiziellen Standard derselbe, aber ich habe keine Kopie auf meiner aktuellen Maschine)
(Betonung meiner)
6 Wenn der Wert des Operanden des delete-expression kein Nullzeigerwert ist, ruft der delete-expression den Destruktor (falls vorhanden) für den Befehl auf Objekt oder die Elemente des Arrays werden gelöscht. Im Falle eines Array werden die Elemente in der Reihenfolge der abnehmenden Adresse zerstört (dh in umgekehrter Reihenfolge der Fertigstellung ihres Konstruktors; siehe 12.6.2).
7 Wenn der Wert des Operanden des delete-expression kein Nullzeigerwert ist, dann:
(7.1) - Wenn der Zuordnungsaufruf für den new-expression für das zu löschende Objekt nicht ausgelassen wurde und die Zuordnung nicht erweitert wurde (5.3.4), wird der delete-expression soll eine Freigabe-Funktion aufrufen (3.7.4.2). Der Wert, der vom Zuweisungsaufruf des neuen Ausdrucks zurückgegeben wird, muss als erstes Argument an die Deallokationsfunktion übergeben werden.
(7.2) - Andernfalls, wenn die Zuweisung erweitert wurde oder durch Erweiterung der Zuweisung eines anderen neuen Ausdrucks und des Löschausdrucks für jeden anderen Zeiger bereitgestellt wurde Wert, der von einem neuen Ausdruck erzeugt wurde, für den der erweiterte erweiterte Ausdruck zur Verfügung gestellt wurde delete-expression soll eine Freigabe-Funktion aufrufen. Der Wert, der vom Zuweisungsaufruf des erweiterten new-expressions zurückgegeben wird, muss als erstes Argument an die Deallokationsfunktion übergeben werden.
(7.3) - Andernfalls ruft der delete-expression keinen a auf Freigabefunktion (3.7.4.2).
Ansonsten ist nicht angegeben, ob die Freigabe-Funktion aufgerufen wird. [ Hinweis: Die Funktion zum Aufheben der Zuweisung wird unabhängig davon aufgerufen, ob der Destruktor für das Objekt oder ein Element des Arrays eine Ausnahme auslöst. - Endnote ]
Die Notiz am Ende besagt, dass die Deallokationsfunktion aufgerufen werden muss, selbst wenn der Destruktor eine Ausnahme auslöst.
Ich bin mir nicht sicher, welche Evolution des Standards zuerst die Dinge buchstabiert hat, aber basierend auf dem Obigen bleiben die Klauseln wahrscheinlich in Abschnitt 5.3.5 (tag [expr.delete]).
Der Destruktor wird vor dem Aufruf des Löschoperators aufgerufen. Siehe cppreference - Ausdruck löschen
Wenn Ausdruck kein Nullzeiger ist, ruft der Löschausdruck den Destruktor (falls vorhanden) für das Objekt auf, das zerstört wird, oder für jedes Element des Arrays, das zerstört wird (ausgehend vom letzten Element zum ersten Element des Arrays) ). Danach, wenn der passende new-Ausdruck nicht mit einem anderen new-Ausdruck kombiniert wurde (seit C ++ 14), ruft der delete-Ausdruck die Deallocation-Funktion entweder operator delete (für die erste Version des Ausdrucks) oder operator delete [] (für die zweite Version des Ausdrucks).
Aufgrund dieser Reihenfolge von Operationen wird der Destruktor aufgerufen und löst eine Ausnahme aus, bevor Ihre überladene Version des Löschoperators aufgerufen wird.
Tags und Links c++ c++11 exception destructor delete-operator