Udostępnij przez


Obsługa wyjątków strukturalnych w języku C++

Główną różnicą między obsługą wyjątków ustrukturyzowanych języka C (SEH) i obsługą wyjątków C++ jest to, że transakcje modelu obsługi wyjątków w języku C++ w typach, podczas gdy model obsługi wyjątków ustrukturyzowanych języka C obsługuje wyjątki jednego typu; w szczególności . unsigned int Oznacza to, że wyjątki języka C są identyfikowane przez niepodpisaną wartość całkowitą, podczas gdy wyjątki języka C++ są identyfikowane przez typ danych. Po wystąpieniu wyjątku strukturalnego w języku C każdy możliwy program obsługi wykonuje filtr, który sprawdza kontekst wyjątku języka C i określa, czy zaakceptować wyjątek, przekazać go do innej procedury obsługi, czy zignorować. Gdy wyjątek jest zgłaszany w języku C++, może być dowolnego typu.

Druga różnica polega na tym, że model obsługi wyjątków ustrukturyzowanych języka C jest określany jako asynchroniczny, ponieważ wyjątki występują pomocnicze do normalnego przepływu sterowania. Mechanizm obsługi wyjątków języka C++ jest w pełni synchroniczny, co oznacza, że wyjątki występują tylko wtedy, gdy są zgłaszane.

Jeśli używasz opcji /EHs lub /EHsc kompilatora, żadne procedury obsługi wyjątków języka C++ nie obsługują wyjątków strukturalnych. Te wyjątki są obsługiwane tylko przez __except programy obsługi wyjątków ustrukturyzowanych lub __finally procedury obsługi zakończenia ze strukturą. Aby uzyskać informacje, zobacz Obsługa wyjątków strukturalnych (C/C++).

W ramach /EHa opcji kompilatora, jeśli wyjątek języka C jest zgłaszany w programie C++, można go obsłużyć przez program obsługi wyjątków ze strukturą ze skojarzonym filtrem lub przez program obsługi języka C++catch, w zależności od tego, która wartość jest dynamicznie zbliżona do kontekstu wyjątku. Na przykład ten przykładowy program C++ zgłasza wyjątek C wewnątrz kontekstu C++ try :

Przykład — przechwytywanie wyjątku języka C w bloku catch języka 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.

Klasy otoki wyjątków języka C

W prostym przykładzie, tak jak powyżej, wyjątek języka C można przechwycić tylko przez program obsługi wielokropka (...). catch Brak informacji na temat typu lub rodzaju wyjątku jest przekazywany do modułu obsługi. Chociaż ta metoda działa, w niektórych przypadkach można zdefiniować transformację między dwoma modelami obsługi wyjątków, tak aby każdy wyjątek C był skojarzony z określoną klasą. Aby przekształcić klasę, można zdefiniować klasę "otoki" wyjątku języka C, która może być używana lub pochodzi z klasy w celu przypisania określonego typu klasy do wyjątku C. W ten sposób każdy wyjątek języka C może być obsługiwany oddzielnie przez określoną procedurę obsługi języka C++ catch , a nie wszystkie w jednej procedurze obsługi.

Klasa otoki może mieć interfejs składający się z niektórych funkcji składowych, które określają wartość wyjątku i dostęp do rozszerzonych informacji kontekstu wyjątku dostarczonych przez model wyjątków C. Możesz również zdefiniować domyślny konstruktor i konstruktor, który akceptuje unsigned int argument (aby zapewnić podstawową reprezentację wyjątku języka C) i konstruktor kopiujący bitowo. Oto możliwa implementacja klasy otoki wyjątków języka 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;
   }
};

Aby użyć tej klasy, zainstaluj niestandardową funkcję tłumaczenia wyjątków języka C wywoływaną przez mechanizm obsługi wyjątków wewnętrznych za każdym razem, gdy zgłaszany jest wyjątek języka C. W funkcji tłumaczenia można zgłosić dowolny typ wyjątku (np SE_Exception . typ lub typ klasy pochodzącej z SE_Exceptionklasy ), który może zostać przechwycony przez odpowiednią zgodną procedurę obsługi języka C++ catch . Funkcja tłumaczenia może zamiast tego zwrócić wartość, która wskazuje, że nie obsługuje wyjątku. Jeśli sama funkcja tłumaczenia zgłasza wyjątek języka C, wywołana jest przerwanie .

Aby określić niestandardową funkcję tłumaczenia, wywołaj funkcję _set_se_translator nazwą funkcji tłumaczenia jako pojedynczy argument. Funkcja tłumaczenia, którą piszesz, jest wywoływana raz dla każdej wywołania funkcji na stosie, który zawiera try bloki. Nie ma domyślnej funkcji tłumaczenia; Jeśli nie określisz go przez wywołanie _set_se_translator, wyjątek języka C może zostać przechwycony tylko przez program obsługi wielokropka catch .

Przykład — używanie niestandardowej funkcji tłumaczenia

Na przykład, poniższy kod instaluje niestandardową funkcję tłumaczenia i następnie zgłasza wyjątek C, który jest otoczony przez klasę 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

Zobacz też

Mieszanie wyjątków C (ustrukturyzowanych) i C++