Ošetření strukturovaných výjimek v C++

Hlavní rozdíl mezi zpracováním výjimek strukturovaného jazyka C (SEH) a zpracováním výjimek jazyka C++ spočívá v tom, že model zpracování výjimek jazyka C++ se zabývá typy, zatímco model strukturovaného zpracování výjimek jazyka C se zabývá výjimkami jednoho typu; konkrétně , unsigned int. To znamená, že výjimky jazyka C jsou identifikovány celočíselnou hodnotou bez znaménka, zatímco výjimky jazyka C++ jsou identifikovány datovým typem. Když je v jazyce C vyvolána strukturovaná výjimka, každá možná obslužná rutina spustí filtr, který prozkoumá kontext výjimky jazyka C a určí, jestli má výjimku přijmout, předat ji jiné obslužné rutině nebo ji ignorovat. Jakmile je vyvolána výjimka v jazyce C++, může být libovolného typu.

Druhý rozdíl spočívá v tom, že model zpracování strukturovaných výjimek jazyka C se označuje jako asynchronní, protože výjimky se vyskytují sekundární pro normální tok řízení. Mechanismus zpracování výjimek jazyka C++ je plně synchronní, což znamená, že k výjimkám dochází pouze v případě, že jsou vyvolány.

Pokud použijete možnost kompilátoru /EHs nebo /EHsc , žádné obslužné rutiny výjimek jazyka C++ nezpracují strukturované výjimky. Tyto výjimky jsou zpracovávány pouze strukturovanými __except obslužnými rutinami výjimek nebo __finally obslužnými rutinami strukturovaného ukončení. Informace najdete v tématu Strukturované zpracování výjimek (C/C++).

Pokud je v programu jazyka C++ vyvolána výjimka jazyka C, je možné ji zpracovat pomocí strukturované obslužné rutiny výjimky s přidruženým filtrem nebo obslužnou rutinou jazyka C++catch, podle toho, co je dynamicky blíž kontextu výjimky. Tento ukázkový program C++ například vyvolá výjimku jazyka C v kontextu jazyka C++ try :

Příklad – Zachycení výjimky jazyka C v bloku zachycení jazyka C++

// 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.

Třídy obálky výjimek jazyka C

V jednoduchém příkladu jako výše lze výjimku jazyka C zachytit pouze obslužnou rutinou se třemi tečkou (...). catch Obslužné rutině není dodána žádná informace o typu nebo povaze výjimky. I když tato metoda funguje, v některých případech můžete chtít definovat transformaci mezi dvěma modely zpracování výjimek, aby každá výjimka jazyka C byla přidružena ke konkrétní třídě. Chcete-li jej transformovat, můžete definovat třídu "obálka" výjimky jazyka C, která se dá použít nebo odvozena, aby bylo možné přiřadit určitý typ třídy výjimce jazyka C. Každá výjimka jazyka C tak může být zpracována zvlášť konkrétní obslužnou rutinou jazyka C++ catch místo všech v jedné obslužné rutině.

Třída zabalení může obsahovat rozhraní skládající se z některých členských funkcí, které určují hodnotu výjimky a které přistupují k rozšířeným kontextovým informacím poskytnutým modelem zpracování výjimek jazyka C. Můžete také chtít definovat výchozí konstruktor a konstruktor, který přijímá unsigned int argument (pro poskytnutí základní reprezentace výjimek jazyka C) a bitový konstruktor kopírování. Tady je možná implementace třídy obálky výjimek jazyka C:

// 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;
   }
};

Chcete-li použít tuto třídu, nainstalujte vlastní funkci překladu výjimek jazyka C, která je volána interním mechanismem zpracování výjimek při každém vyvolání výjimky jazyka C. V rámci funkce překladu můžete vyvolat libovolnou SE_Exception typovou výjimku (třeba typ nebo typ třídy odvozený z SE_Exception), který lze zachytit odpovídající obslužnou rutinou jazyka C++ catch . Funkce překladu může místo toho vrátit, což znamená, že nezpracovala výjimku. Pokud samotná funkce překladu vyvolá výjimku jazyka C, zavolá se ukončení .

Pokud chcete zadat vlastní funkci překladu , zavolejte funkci _set_se_translator s názvem funkce překladu jako jeho jediným argumentem. Funkce překladu, kterou napíšete, se volá jednou pro každé vyvolání funkce v zásobníku, který obsahuje try bloky. Neexistuje žádná výchozí funkce překladu; Pokud ho nezadáte voláním _set_se_translator, lze výjimku jazyka C zachytit pouze obslužnou rutinou tří teček catch .

Příklad – Použití vlastní funkce překladu

Následující kód například nainstaluje vlastní funkci překladu a poté vyvolá výjimku jazyka C, která je zabalena do třídy SE_Exception:

// 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

Viz také

Kombinování výjimek jazyka C (strukturované) a C++