91 Stimmen

Wie ist die C++-Laufzeitumgebung zur Behandlung von Ausnahmen implementiert?

Mich interessiert, wie der Mechanismus zur Behandlung von Ausnahmen in C++ funktioniert. Insbesondere, wo wird das Ausnahmeobjekt gespeichert und wie wird es durch mehrere Bereiche weitergegeben, bis es abgefangen wird? Wird es in einem globalen Bereich gespeichert?

Da dies Compiler-spezifisch sein könnte, könnte jemand dies im Zusammenhang mit der g++ Compiler-Suite erklären?

57voto

MSalters Punkte 166675

Die Umsetzung kann unterschiedlich sein, aber es gibt einige grundlegende Ideen, die sich aus den Anforderungen ergeben.

Das Exception-Objekt selbst ist ein Objekt, das in einer Funktion erzeugt und in einem ihrer Aufrufer zerstört wird. Daher ist es normalerweise nicht möglich, das Objekt auf dem Stack zu erstellen. Andererseits sind viele Ausnahmeobjekte nicht sehr groß. Man kann also z.B. einen 32-Byte-Puffer erstellen und auf den Heap überlaufen lassen, wenn ein größeres Ausnahmeobjekt benötigt wird.

Für die eigentliche Übertragung der Kontrolle gibt es zwei Strategien. Die eine besteht darin, genügend Informationen im Stapel selbst aufzuzeichnen, um den Stapel abzuwickeln. Dabei handelt es sich im Wesentlichen um eine Liste von auszuführenden Destruktoren und Ausnahmebehandlern, die die Ausnahme abfangen könnten. Wenn eine Ausnahme auftritt, wird der Stapel durch die Ausführung dieser Destruktoren zurückgespult, bis man eine passende Abfangfunktion findet.

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 verlassen wurden. Diese werden dann in den statischen Tabellen nachgeschlagen, um zu bestimmen, wo die ausgelöste Ausnahme behandelt wird, und welche Destruktoren dazwischen laufen. Dies bedeutet, dass weniger Ausnahmen auf dem Stack liegen; Rücksprungadressen werden ohnehin benötigt. Bei den Tabellen handelt es sich um zusätzliche Daten, aber der Compiler kann sie in ein bedarfsgesteuertes Segment des Programms einfügen.

22voto

Martin York Punkte 245363

Dies ist in 15.1 Auslösen einer Ausnahme des Standards definiert.

Der Wurf erzeugt ein temporäres Objekt.
Wie der Speicher für dieses temporäre Objekt zugewiesen wird, ist nicht spezifiziert.

Nach der Erstellung des temporären Objekts wird die Kontrolle an den nächstgelegenen Handler im Aufrufstapel übergeben, wobei der Stapel zwischen dem throw- und dem catch-Punkt abgewickelt wird. Beim Abbau des Stacks werden alle Stack-Variablen in umgekehrter Reihenfolge der Erstellung zerstört.

Sofern die Ausnahme nicht erneut ausgelöst wird, wird das temporäre Element am Ende des Handlers, in dem es abgefangen wurde, zerstört.

Hinweis: Wenn Sie per Referenz abfangen, bezieht sich die Referenz auf das temporäre Objekt, wenn Sie per Wert abfangen, wird das temporäre Objekt in den Wert kopiert (und erfordert daher einen Kopierkonstruktor).

Ratschlag von S. Meyers (Catch by const reference).

try
{
    // do stuff
}
catch(MyException const& x)
{
}
catch(std::exception const& x)
{
}

13voto

Sie könnten einen Blick darauf werfen ici für eine ausführliche Erklärung.

Es kann auch hilfreich sein, einen Blick auf einen Trick zu werfen, der in einfachem C verwendet wird, um eine grundlegende Art der Ausnahmebehandlung zu implementieren. Dazu gehört die Verwendung von setjmp() und longjmp() auf folgende Weise: Ersteres speichert den Stack, um den Exception-Handler zu markieren (wie "catch"), während letzteres verwendet wird, um einen Wert zu "werfen". Der "geworfene" Wert wird so betrachtet, als ob er von einer aufgerufenen Funktion zurückgegeben worden wäre. Der "Try-Block" endet, wenn setjmp() erneut aufgerufen wird oder wenn die Funktion zurückkehrt.

10voto

Jules May Punkte 683

Ich weiß, dass dies eine alte Frage ist, aber es gibt eine sehr gute Darstellung, die sowohl die Methoden, die in jedem von gcc und VC hier erklärt: http://www.hexblog.com/wp-content/uploads/2012/06/Recon-2012-Skochinsky-Compiler-Internals.pdf

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X