Behandeln strukturierter Ausnahmen in C++

Der Hauptunterschied zwischen der C-strukturierten Ausnahmebehandlung (SEH) und der C++-Ausnahmebehandlung besteht darin, dass das C++-Ausnahmebehandlungsmodell Typen behandelt, während sich das C-strukturierte Ausnahmebehandlungsmodell mit Ausnahmen eines Typs befasst; insbesondere . unsigned int Das heißt, C-Ausnahmen werden durch einen nicht signierten ganzzahligen Wert identifiziert, während C++-Ausnahmen vom Datentyp identifiziert werden. Wenn eine strukturierte Ausnahme in C ausgelöst wird, führt jeder mögliche Handler einen Filter aus, der den C-Ausnahmekontext untersucht und bestimmt, ob die Ausnahme akzeptiert, an einen anderen Handler übergeben oder ignoriert wird. Wenn eine Ausnahme in C++ ausgelöst wird, kann sie einem beliebigen Typ angehören.

Ein zweiter Unterschied besteht darin, dass das C-strukturierte Ausnahmebehandlungsmodell als asynchron bezeichnet wird, da Ausnahmen sekundär zum normalen Kontrollfluss auftreten. Der C++-Ausnahmebehandlungsmechanismus ist vollständig synchron, was bedeutet, dass Ausnahmen nur auftreten, wenn sie ausgelöst werden.

Wenn Sie die /EHs- oder /EHsc-Compileroption verwenden, behandeln keine C++-Ausnahmehandler strukturierte Ausnahmen. Diese Ausnahmen werden nur von __except strukturierten Ausnahmehandlern oder __finally strukturierten Beendigungshandlern behandelt. Weitere Informationen finden Sie unter Strukturierte Ausnahmebehandlung (C/C++).

Wenn eine C-Ausnahme in einem C++-Programm ausgelöst wird, kann sie unter der /EHa-Compileroption von einem strukturierten Ausnahmehandler mit dem zugeordneten Filter oder einem C++ catch -Handler behandelt werden, je nachdem, welcher Wert dynamisch dem Ausnahmekontext näher kommt. In diesem C++-Beispielprogramm wird beispielsweise eine C-Ausnahme innerhalb eines C++ try -Kontexts ausgelöst:

Beispiel: Erfassen einer C-Ausnahme in einem C++-Catch-Block

// exceptions_Exception_Handling_Differences.cpp
// compile with: /EHa
#include <iostream>

using namespace std;
void SEHFunc( void );

int main() {
   try {
      SEHFunc();
   }
   catch( ... ) {
      cout << "Caught a C exception."<< endl;
   }
}

void SEHFunc() {
   __try {
      int x, y = 0;
      x = 5 / y;
   }
   __finally {
      cout << "In finally." << endl;
   }
}
In finally.
Caught a C exception.

C-Ausnahmewrapperklassen

In einem einfachen Beispiel wie oben kann die C-Ausnahme nur von einem Auslassungszeichen (...) catch Handler abgefangen werden. Es werden keine Informationen über den Typ oder die Art der Ausnahme an den Handler übermittelt. Während diese Methode funktioniert, können Sie in einigen Fällen eine Transformation zwischen den beiden Ausnahmebehandlungsmodellen definieren, sodass jede C-Ausnahme einer bestimmten Klasse zugeordnet ist. Um eine zu transformieren, können Sie eine C-Ausnahme "Wrapper"-Klasse definieren, die verwendet oder abgeleitet werden kann, um einen bestimmten Klassentyp einer C-Ausnahme zuzuordnen. Auf diese Weise kann jede C-Ausnahme separat von einem bestimmten C++ catch -Handler behandelt werden, anstatt alle in einem einzelnen Handler.

Die Wrapperklasse enthält eventuell eine Schnittstelle, die aus mehreren Memberfunktionen besteht, die den Wert der Ausnahme bestimmen und auf die erweiterten Ausnahmekontextinformationen zugreifen, die vom C-Ausnahmemodell bereitgestellt werden. Möglicherweise möchten Sie auch einen Standardkonstruktor und einen Konstruktor definieren, der ein unsigned int Argument akzeptiert (um die zugrunde liegende C-Ausnahmedarstellung bereitzustellen) und einen bitweisen Kopierkonstruktor. Hier ist eine mögliche Implementierung einer C-Ausnahmewrapperklasse:

// exceptions_Exception_Handling_Differences2.cpp
// compile with: /c
class SE_Exception {
private:
   SE_Exception() {}
   SE_Exception( SE_Exception& ) {}
   unsigned int nSE;
public:
   SE_Exception( unsigned int n ) : nSE( n ) {}
   ~SE_Exception() {}
   unsigned int getSeNumber() {
      return nSE;
   }
};

Um diese Klasse zu verwenden, installieren Sie eine benutzerdefinierte C-Ausnahmeübersetzungsfunktion, die jedes Mal, wenn eine C-Ausnahme ausgelöst wird, vom internen Ausnahmebehandlungsmechanismus aufgerufen wird. Innerhalb Der Übersetzungsfunktion können Sie eine beliebige typierte Ausnahme (z. B. einen SE_Exception Typ oder einen von ) abgeleiteten SE_ExceptionKlassentyp auslösen, der von einem geeigneten passenden C++ catch -Handler abgefangen werden kann. Die Übersetzungsfunktion kann stattdessen zurückgegeben werden, was angibt, dass sie die Ausnahme nicht behandelt hat. Wenn die Übersetzungsfunktion selbst eine C-Ausnahme auslöst, wird "Terminate " aufgerufen.

Um eine benutzerdefinierte Übersetzungsfunktion anzugeben, rufen Sie die _set_se_translator-Funktion mit dem Namen der Übersetzungsfunktion als einzelnes Argument auf. Die übersetzungsfunktion, die Sie schreiben, wird einmal für jeden Funktionsaufruf auf dem Stapel aufgerufen, der Blöcke enthält try . Es gibt keine Standardübersetzungsfunktion; Wenn Sie eine nicht angeben, indem Sie _set_se_translator aufrufen, kann die C-Ausnahme nur von einem Ellipsenhandler catch abgefangen werden.

Beispiel: Verwenden einer benutzerdefinierten Übersetzungsfunktion

Der folgende Code installiert beispielsweise eine benutzerdefinierte Übersetzungsfunktion und löst anschließend eine C-Ausnahme aus, die von der SE_Exception-Klasse umschlossen wird:

// exceptions_Exception_Handling_Differences3.cpp
// compile with: /EHa
#include <stdio.h>
#include <eh.h>
#include <windows.h>

class SE_Exception {
private:
   SE_Exception() {}
   unsigned int nSE;
public:
   SE_Exception( SE_Exception& e) : nSE(e.nSE) {}
   SE_Exception(unsigned int n) : nSE(n) {}
   ~SE_Exception() {}
   unsigned int getSeNumber() { return nSE; }
};

void SEFunc() {
    __try {
        int x, y = 0;
        x = 5 / y;
    }
    __finally {
        printf_s( "In finally\n" );
    }
}

void trans_func( unsigned int u, _EXCEPTION_POINTERS* pExp ) {
    printf_s( "In trans_func.\n" );
    throw SE_Exception( u );
}

int main() {
    _set_se_translator( trans_func );
    try {
        SEFunc();
    }
    catch( SE_Exception e ) {
        printf_s( "Caught a __try exception with SE_Exception.\n" );
        printf_s( "nSE = 0x%x\n", e.getSeNumber() );
    }
}
In trans_func.
In finally
Caught a __try exception with SE_Exception.
nSE = 0xc0000094

Siehe auch

Mischen von C(Strukturierten) und C++-Ausnahmen