Erstens ist mir klar, warum es in C ++ kein 'finally'-Konstrukt gibt. Eine lange Diskussion über Kommentare zu einer anderen Frage scheint jedoch eine gesonderte Frage zu rechtfertigen.
Abgesehen von dem Problem, dass finally
C # und Java grundsätzlich nur einmal (== 1) pro Bereich existieren können und ein einzelner Bereich mehrere (== n) C ++ - Destruktoren haben kann, denke ich, dass sie im Wesentlichen dasselbe sind. (Mit einigen technischen Unterschieden.)
Ein anderer Benutzer argumentierte jedoch :
... Ich habe versucht zu sagen, dass ein dtor von Natur aus ein Werkzeug für (Sematik freigeben) und schließlich von Natur aus ein Werkzeug für (Semantik festlegen) ist. Wenn Sie nicht sehen, warum: Überlegen Sie, warum es legitim ist, Ausnahmen in finally-Blöcken übereinander zu werfen, und warum dies nicht für Destruktoren gilt. (In gewissem Sinne handelt es sich um eine Daten- / Kontrollsache. Destruktoren dienen der Freigabe von Daten und schließlich der Freigabe von Kontrolle. Sie unterscheiden sich; es ist bedauerlich, dass C ++ sie zusammenhält.)
Kann jemand das klären?
quelle
A
und vorB
. Wenn ein Thread ausgelöst wird, sollte das Zurücksetzen derA's
Transaktion nicht die zugewiesenen Ressourcen zerstörenB
, z. In der Regel ist der Heapspeicher in C ++ jedoch weiterhin an Objekte auf dem Stapel gebunden.std::vector
Objekt befindet sich möglicherweise auf dem Stapel, zeigt jedoch auf den Speicher des Heapspeichers. In diesem Fall werden sowohl das Vektorobjekt (auf dem Stapel) als auch dessen Inhalt (auf dem Heapspeicher) während des Abwickelns des Stapels freigegeben Wenn Sie den Vektor auf dem Stapel zerstören, wird ein Destruktor aufgerufen, der den zugehörigen Speicher auf dem Heap freigibt (und diese Heap-Elemente ebenfalls zerstört). In der Regel befinden sich die meisten C ++ - Objekte aus Gründen der Ausnahmesicherheit auf dem Stapel, auch wenn sie nur auf den Arbeitsspeicher auf dem Heap verweisen, wodurch die Freigabe des Heap- und des Stapelspeichers beim Abwickeln des Stapels automatisiert wird.Ich bin froh, dass du dies als Frage gepostet hast. :)
Ich habe versucht zu sagen, dass Destruktoren und
finally
konzeptionell unterschiedlich sind:finally
ist für die Rückkehr zum Anrufer ( Kontrolle )Betrachten Sie beispielsweise diesen hypothetischen Pseudocode:
finally
Hier wird ein Steuerungsproblem und kein Ressourcenverwaltungsproblem vollständig gelöst.Es wäre aus verschiedenen Gründen nicht sinnvoll, dies in einem Destruktor zu tun:
logfile.print
zu scheitern, wohingegen Zerstörung (konzeptionell) nicht scheitern kannHier ist ein weiteres Beispiel, diesmal wie in Javascript:
Auch im obigen Beispiel müssen keine Ressourcen freigegeben werden.
In der Tat, das
finally
ist Block Erwerb Ressourcen intern ihr Ziel zu erreichen, die möglicherweise ausfallen könnten. Daher ist es nicht sinnvoll, einen Destruktor zu verwenden (falls Javascript einen hat).Andererseits in diesem Beispiel:
finally
eine Ressource zerstört,b
. Es ist ein Datenproblem. Das Problem besteht nicht darin, die Kontrolle sauber an den Anrufer zurückzugeben, sondern vielmehr, Ressourcenlecks zu vermeiden.Ein Ausfall ist keine Option und sollte (konzeptionell) niemals auftreten.
Jedes Release von
b
ist zwangsläufig mit einer Akquisition verbunden, und es ist sinnvoll, RAII zu verwenden.Mit anderen Worten, nur weil Sie entweder zum Simulieren verwenden können, bedeutet dies nicht, dass beide ein und dasselbe Problem sind oder dass beide geeignete Lösungen für beide Probleme sind.
quelle
finally
die hauptsächlich zur Freigabe von Ressourcen (ohne Arbeitsspeicher) verwendet wird?finally
.finally
Klausel wieder auf Normal zurücksetzen. Die C ++ - Weltanschauung würde eine Klasse einführen, die diese "Ressource" einer Zuweisung zu einer pseudo-globalen Variablen verwaltet. Welchen begrifflichen Sinn macht das? Destruktoren sind jedoch C ++ 'Hammer für die Ausführung des erforderlichen Blockende-Codes.Die Antwort von k3b drückt es wirklich gut aus:
Bezüglich "Ressourcen" verweise ich gerne auf Jon Kalb: RAII sollte bedeuten, dass Verantwortungsübernahme Initialisierung ist .
Wie auch immer, was implizites vs. explizites betrifft, scheint dies wirklich so zu sein:
Ich denke, das ist es für den konzeptionellen Teil, ...
... jetzt gibt es meiner Meinung nach einige interessante Details:
fault
Block zum Ausführen von Code gibt, der nur im Falle eines außergewöhnlichen Bereichs-Exits ausgeführt werden sollte.SCOPE_EXIT
,SCOPE_FAIL
undSCOPE_SUCCESS
in der Torheitsbibliothek . Siehe Andrei Alexandrescu: Fehlerbehandlung in C ++ / Declarative Control Flow (gehalten auf der NDC 2014 )Ich denke auch nicht, dass c'tor / d'tor konzeptionell etwas "erwerben" oder "erstellen" muss, abgesehen von der Verantwortung, Code im Destruktor auszuführen. Welches ist, was schließlich auch tut: Führen Sie einen Code aus.
Und während Code in einem finally-Block mit Sicherheit eine Ausnahme auslösen kann, reicht mir der Unterschied nicht aus, um zu sagen, dass sie sich konzeptionell über explizit und implizit unterscheiden.
(Außerdem bin ich überhaupt nicht davon überzeugt, dass "guter" Code endlich herauskommen sollte - vielleicht ist das eine ganz andere Frage an sich.)
quelle
observer
Beispiel, dass das Werfen eine wirklich schlechte Idee wäre.) Sie können gerne einen Chat eröffnen, wenn Sie dies weiter diskutieren möchten. Es hat auf jeden Fall Spaß gemacht, über Ihre Argumente nachzudenken. Prost.