Ich bin fasziniert davon, wie der C ++ - Ausnahmebehandlungsmechanismus funktioniert. Wo wird das Ausnahmeobjekt gespeichert und wie breitet es sich über mehrere Bereiche aus, bis es abgefangen wird? Wird es in einem globalen Bereich gespeichert?
Da dies compilerspezifisch sein könnte, könnte jemand dies im Kontext der g ++ - Compilersuite erklären?
c++
exception
error-handling
language-implementation
Paul Joseph
quelle
quelle
Antworten:
Die Implementierungen können abweichen, aber es gibt einige grundlegende Ideen, die sich aus den Anforderungen ergeben.
Das Ausnahmeobjekt selbst ist ein Objekt, das in einer Funktion erstellt und in einem Aufrufer davon zerstört wurde. Daher ist es normalerweise nicht möglich, das Objekt auf dem Stapel zu erstellen. Andererseits sind viele Ausnahmeobjekte nicht sehr groß. Ergo kann man zB einen 32-Byte-Puffer und einen Überlauf zum Heap erstellen, wenn tatsächlich ein größeres Ausnahmeobjekt benötigt wird.
Für die tatsächliche Übertragung der Kontrolle gibt es zwei Strategien. Eine besteht darin, genügend Informationen im Stapel selbst aufzuzeichnen, um den Stapel abzuwickeln. Dies ist im Grunde eine Liste der auszuführenden Destruktoren und Ausnahmebehandlungsroutinen, die die Ausnahme möglicherweise abfangen. Wenn eine Ausnahme auftritt, führen Sie den Stapel aus, der diese Destruktoren ausführt, bis Sie einen passenden Fang finden.
Die zweite Strategie verschiebt diese Informationen in Tabellen außerhalb des Stapels. Wenn nun eine Ausnahme auftritt, wird der Aufrufstapel verwendet, um herauszufinden, welche Bereiche eingegeben, aber nicht beendet werden. Diese werden dann in den statischen Tabellen nachgeschlagen, um festzustellen, wo die ausgelöste Ausnahme behandelt wird und welche Destruktoren dazwischen ausgeführt werden. Dies bedeutet, dass auf dem Stapel weniger Ausnahmekosten anfallen. Absenderadressen werden sowieso benötigt. Die Tabellen sind zusätzliche Daten, aber der Compiler kann sie in ein bedarfsgesteuertes Segment des Programms einfügen.
quelle
free()
oder ein fehltfclose()
.Dies ist in 15.1 Auslösen einer Ausnahme vom Standard definiert.
Der Wurf erzeugt ein temporäres Objekt.
Wie der Speicher für dieses temporäre Objekt zugewiesen wird, ist nicht angegeben.
Nach dem Erstellen des temporären Objekts wird die Steuerung an den nächstgelegenen Handler im Aufrufstapel übergeben. Abwickeln des Stapels zwischen Wurf- und Fangpunkt. Während des Abwickelns des Stapels werden alle Stapelvariablen in umgekehrter Reihenfolge der Erstellung zerstört.
Sofern die Ausnahme nicht erneut ausgelöst wird, wird die temporäre Ausnahme am Ende des Handlers zerstört, an dem sie abgefangen wurde.
Hinweis: Wenn Sie nach Referenz abfangen, bezieht sich die Referenz auf das temporäre Objekt. Wenn Sie nach Wert abfangen, wird das temporäre Objekt in den Wert kopiert (und erfordert daher einen Kopierkonstruktor).
Ratschläge von S.Meyers (Catch by const reference).
quelle
Sie könnten einen Blick hier für eine ausführliche Erklärung.
Es kann auch hilfreich sein, einen Trick zu betrachten, der in C verwendet wird, um eine grundlegende Art der Ausnahmebehandlung zu implementieren. Dies beinhaltet die Verwendung von setjmp () und longjmp () auf folgende Weise: Ersteres speichert den Stapel, um den Ausnahmebehandler zu markieren (wie "catch"), während letzteres verwendet wird, um einen Wert zu "werfen". Der "geworfene" Wert wird so gesehen, als ob er von einer aufgerufenen Funktion zurückgegeben wurde. Der "try block" endet, wenn setjmp () erneut aufgerufen wird oder wenn die Funktion zurückkehrt.
quelle
Ich weiß, dass dies eine alte Frage ist, aber es gibt eine sehr gute Darstellung, in der sowohl die in gcc als auch in VC verwendeten Methoden hier erläutert werden: http://www.hexblog.com/wp-content/uploads/2012/06/Recon- 2012-Skochinsky-Compiler-Internals.pdf
quelle