Grundlegende Konzepte zur Verwendung verwalteter Ausnahmen

In diesem Thema wird die Ausnahmebehandlung in verwalteten Anwendungen erläutert. Das heißt, eine Anwendung, die mit der Compileroption /clr kompiliert wird.

Inhalt

Hinweise

Wenn Sie mit der Option "/clr " kompilieren, können Sie CLR-Ausnahmen behandeln sowie standardklasse Exception viele nützliche Methoden zum Verarbeiten von CLR-Ausnahmen bereitstellen und wird als Basisklasse für benutzerdefinierte Ausnahmeklassen empfohlen.

Das Abfangen von Ausnahmetypen, die von einer Schnittstelle abgeleitet sind, wird unter "/clr" nicht unterstützt. Außerdem ermöglicht ihnen die Common Language Runtime nicht das Abfangen von Stapelüberlaufausnahmen; Eine Stapelüberlaufausnahme beendet den Prozess.

Weitere Informationen zu Unterschieden bei der Ausnahmebehandlung in verwalteten und nicht verwalteten Anwendungen finden Sie unter "Unterschiede beim Verhalten der Ausnahmebehandlung unter verwalteten Erweiterungen für C++".

Auslösen von Ausnahmen unter /clr

Der C++-Auslöserausdruck wird erweitert, um einen Handle auf einen CLR-Typ auszulösen. Im folgenden Beispiel wird ein benutzerdefinierter Ausnahmetyp erstellt und anschließend eine Instanz dieses Typs ausgelöst:

// clr_exception_handling.cpp
// compile with: /clr /c
ref struct MyStruct: public System::Exception {
public:
   int i;
};

void GlobalFunction() {
   MyStruct^ pMyStruct = gcnew MyStruct;
   throw pMyStruct;
}

Vor dem Auslösen muss ein Werttyp boxt werden:

// clr_exception_handling_2.cpp
// compile with: /clr /c
value struct MyValueStruct {
   int i;
};

void GlobalFunction() {
   MyValueStruct v = {11};
   throw (MyValueStruct ^)v;
}

Try/Catch-Blöcke für CLR-Erweiterungen

Die gleiche try/catch Blockstruktur kann zum Abfangen von CLR- und systemeigenen Ausnahmen verwendet werden:

// clr_exception_handling_3.cpp
// compile with: /clr
using namespace System;
ref struct MyStruct : public Exception {
public:
   int i;
};

struct CMyClass {
public:
   double d;
};

void GlobalFunction() {
   MyStruct^ pMyStruct = gcnew MyStruct;
   pMyStruct->i = 11;
   throw pMyStruct;
}

void GlobalFunction2() {
   CMyClass c = {2.0};
   throw c;
}

int main() {
   for ( int i = 1; i >= 0; --i ) {
      try {
         if ( i == 1 )
            GlobalFunction2();
         if ( i == 0 )
            GlobalFunction();
      }
      catch ( CMyClass& catchC ) {
         Console::WriteLine( "In 'catch(CMyClass& catchC)'" );
         Console::WriteLine( catchC.d );
      }
      catch ( MyStruct^ catchException ) {
         Console::WriteLine( "In 'catch(MyStruct^ catchException)'" );
         Console::WriteLine( catchException->i );
      }
   }
}

Ausgabe

In 'catch(CMyClass& catchC)'
2
In 'catch(MyStruct^ catchException)'
11

Reihenfolge des Abwickelns für C++-Objekte

Das Abwickeln erfolgt für alle C++-Objekte mit Destruktoren, die sich zwischen der auslösenden Funktion und der Behandlungsfunktion auf dem Laufzeitstapel befinden können. Da CLR-Typen auf dem Heap zugeordnet sind, gilt das Entspannen nicht für sie.

Die Reihenfolge der Ereignisse für eine ausgelöste Ausnahme lautet wie folgt:

  1. Die Laufzeit durchläuft den Stapel, der nach der entsprechenden Catch-Klausel sucht, oder im Fall von SEH, einem ausnahmefilter für SEH, um die Ausnahme abzufangen. Catch-Klauseln werden zuerst in lexikalischer Reihenfolge und dann dynamisch nach unten im Aufrufstapel durchsucht.

  2. Sobald der richtige Handler gefunden wurde, wird der Stapel an diesem Punkt entladen. Für jeden Funktionsaufruf im Stapel werden die lokalen Objekte destruktiert, und __finally Blöcke werden von den meisten verschachtelten nach außen ausgeführt.

  3. Sobald der Stapel entwundt ist, wird die Catch-Klausel ausgeführt.

Abfangen nicht verwalteter Typen

Wenn ein nicht verwalteter Objekttyp ausgelöst wird, wird er mit ausnahme des Typs SEHExceptionumschlossen. Bei der Suche nach der entsprechenden catch Klausel gibt es zwei Möglichkeiten.

  • Wenn ein systemeigener C++-Typ gefunden wird, wird die Ausnahme entwrappt und im Vergleich zum gefundenen Typ. Mit diesem Vergleich kann ein systemeigener C++-Typ normal abgefangen werden.

  • Wenn jedoch eine catch Klausel vom Typ SEHException oder eine seiner Basisklassen zuerst untersucht wird, wird die Ausnahme von der Klausel abgefangen. Daher sollten Sie alle Catch-Klauseln platzieren, die systemeigene C++-Typen zuerst vor catch-Klauseln von CLR-Typen abfangen.

Beachten Sie, dass

catch(Object^)

and

catch(...)

fangen alle ausgelösten Typen einschließlich SEH-Ausnahmen ab.

Wenn ein nicht verwalteter Typ von catch(Object^) abgefangen wird, wird das ausgelöste Objekt nicht zerstört.

Beim Auslösen oder Abfangen nicht verwalteter Ausnahmen wird empfohlen, die /EHsc-Compileroption anstelle von /EHs oder /EHa zu verwenden.

Siehe auch

Ausnahmebehandlung
safe_cast
Ausnahmebehandlung