Ausnahmen und Stapelentladung in C++
Im C++-Ausnahme-Mechanismus wird das Steuerelement von der - Anweisung zur ersten catch-Anweisung, die den ausgelösten Typ behandeln kann.Wenn die catch-Anweisung erreicht wird, werden alle automatischen Variablen, die im Bereich zwischen dem Throw und den Anweisungen sind, in einem Prozess zerstört, der als Stapelentladung bezeichnet.In der Stapelentladung wird die Ausführung fortgesetzt, wie folgt:
Steuerung erreicht die try-Anweisung durch normale sequenzielle Ausführung.Der abgesicherte Abschnitt im try-Block wird ausgeführt.
Wenn keine Ausnahme während der Ausführung des abgesicherten Abschnitt ausgelöst wird, werden die catch-Klauseln, die dem try-Block folgen, nicht ausgeführt.Die Ausführung wird bei der Anweisung nach der letzten catch-Klausel fort, die dem zugeordneten try-Block folgt.
Wenn eine Ausnahme während der Ausführung des Abschnitts abgesicherten oder in einer Routine ausgelöst wird, dass der abgesicherte Abschnitt entweder direkt oder indirekt aufruft, wird ein Ausnahmeobjekt vom - Objekt erstellt, das durch den throw Operanden erstellt wird.(Dies bedeutet, dass ein Kopierkonstruktor betroffen sein kann.) An diesem Punkt findet der Compiler nach einer catch-Klausel in einem höheren Ausführungskontext, der eine Ausnahme des Typs, der ausgelöst wird oder für einen catch-Handler behandeln kann, der jeden Typ Ausnahme behandeln kann.Die catch-Handler werden in der Reihenfolge ihrer Darstellung nach der try-Block überprüft.Wenn kein entsprechender Handler gefunden wird, wird der nächste dynamisch umfassende try-Block untersucht.Dieser Prozess wird fortgesetzt, bis der äußerste umschließende try-Block ausgewertet wird.
Wenn ein entsprechender Handler noch nicht gefunden wird, oder wenn eine Ausnahme während des Entladens auftritt, aber bevor der Handler Steuerelement abruft, wird die vordefinierte Laufzeitfunktion terminate aufgerufen.Wenn eine Ausnahme auftritt, nachdem die Ausnahme ausgelöst wurde, jedoch bevor die eine Entladung beginnt, wird terminate aufgerufen.
Wenn ein entsprechender catch-Handler gefunden wird und Variablen als Wert abfängt, wird sein formaler Parameter initialisiert, indem das Ausnahmeobjekt kopiert wird.Wenn er als Verweis abfängt, wird der Parameter so initialisiert, dass er auf das Ausnahmeobjekt verweist.Nachdem der formale Parameter initialisiert wurde, beginnt der Prozess des Entladens des Stapels.Dies schließt die Zerstörung aller automatischen Objekte beinhalten, die vollständig erstellte-aber noch nicht zerstören-zwischen am Anfang des Blocks try waren, der mit dem catch-Handler und der Wurfssite der Ausnahme zugeordnet ist.Zerstörung tritt in umgekehrter Reihenfolge der Konstruktion auf.Der catch-Handler wird und die Programmzusammenfassungsausführung, nachdem das letzte Handler-dass ist, an der ersten Anweisung oder am Konstrukt ausgeführt, das kein catch-Handler ist.Steuerelement kann einen catch-Handler durch eine ausgelöste Ausnahme, nie von eine goto-Anweisung oder eine case Bezeichnung in einer switch-Anweisung nur eingeben.
Stapelentladungsbeispiel
Das folgende Beispiel zeigt, wie der Stapel entladen wird, wenn eine Ausnahme ausgelöst wird.Ausführung auf den Threadsprüngen aus der throw-Anweisung in C zur catch-Anweisung in main und Entladungen jede Funktion währenddessen.Beachten Sie die Reihenfolge, in der die Dummy-Objekte erstellt und anschließend zerstört, wenn sie den Gültigkeitsbereich verlassen.Beachten Sie auch, dass keine Funktion außer main abzuschließen, die die catch-Anweisung enthält.Funktion A gibt nie von seinem Aufruf zu B() zurück, und B gibt nie von seinem Aufruf zu C() zurück.Wenn Sie die Definition des Dummy Zeigers und der entsprechenden Löschungsanweisung Auskommentierung aufheben und dann das Programm ausführen, Sie, dass der Zeiger nicht gelöscht wird.Dies zeigt, was geschehen kann, wenn keine Funktionen Ausnahmegarantie bereitstellen.Weitere Informationen finden Sie unter Gewusst wie: Entwurf für Ausnahmen.Beim Auschecken die catch-Anweisung kommentieren, können Sie beobachten, was geschieht, wenn ein Programm aufgrund eines Ausnahme beendet wird.
#include <string>
#include <iostream>
using namespace std;
class MyException{};
class Dummy
{
public:
Dummy(string s) : MyName(s) { PrintMsg("Created Dummy:"); }
Dummy(const Dummy& other) : MyName(other.MyName){ PrintMsg("Copy created Dummy:"); }
~Dummy(){ PrintMsg("Destroyed Dummy:"); }
void PrintMsg(string s) { cout << s << MyName << endl; }
string MyName;
int level;
};
void C(Dummy d, int i)
{
cout << "Entering FunctionC" << endl;
d.MyName = " C";
throw MyException();
cout << "Exiting FunctionC" << endl;
}
void B(Dummy d, int i)
{
cout << "Entering FunctionB" << endl;
d.MyName = "B";
C(d, i + 1);
cout << "Exiting FunctionB" << endl;
}
void A(Dummy d, int i)
{
cout << "Entering FunctionA" << endl;
d.MyName = " A" ;
// Dummy* pd = new Dummy("new Dummy"); //Not exception safe!!!
B(d, i + 1);
// delete pd;
cout << "Exiting FunctionA" << endl;
}
int main()
{
cout << "Entering main" << endl;
try
{
Dummy d(" M");
A(d,1);
}
catch (MyException& e)
{
cout << "Caught an exception of type: " << typeid(e).name() << endl;
}
cout << "Exiting main." << endl;
char c;
cin >> c;
}
/* Output:
Entering main
Created Dummy: M
Copy created Dummy: M
Entering FunctionA
Copy created Dummy: A
Entering FunctionB
Copy created Dummy: B
Entering FunctionC
Destroyed Dummy: C
Destroyed Dummy: B
Destroyed Dummy: A
Destroyed Dummy: M
Caught an exception of type: class MyException
Exiting main.
*/