Warum wird ein überladenes Löschen nicht aufgerufen, wenn eine Ausnahme in einen Destruktor geworfen wird?

8

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?

%Vor%

Ausgabe:

%Vor%

Live-Demo .

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.

    
Dukeling 12.08.2017, 20:52
quelle

3 Antworten

5

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:

Biagio Festa 12.08.2017, 21:54
quelle
2

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]).

    
Peter 12.08.2017 23:44
quelle
-1

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.

    
Avishai Y 12.08.2017 21:39
quelle