Udostępnij za pośrednictwem


Różnice w obsłudze wyjątków

Główną różnica pomiędzy obsługą wyjątków strukturalnych i obsługą wyjątków C++ jest to, że model obsługi wyjątków C++ operuje na różnych typach , podczas gdy strukturalny model obsługi wyjątków języka C zajmuje się wyjątkami jednego typu — w szczególności unsigned int.Oznacza to, że wyjątki C są identyfikowane przez wartość całkowitą bez znaku, natomiast wyjątki C++ są identyfikowane przez typ danych.Gdy tworzony jest wyjątek w C, każdy możliwy program obsługi wykonuje filtr, który sprawdza kontekst wyjątków C i określa, czy należy zaakceptować wyjątek, przekazać go do innego programu obsługi lub 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 strukturalnych C jest określony, jako "asynchroniczny" w tym wyjątki występują wtórne w stosunku do normalnego przepływu sterowania.Mechanizm obsługi wyjątków C++ jest całkowicie "synchroniczny," co oznacza, że wyjątki występują tylko wtedy kiedy są zgłaszane.

Jeśli wyjątek C jest inicjowany w programie C++, może być obsługiwany przez strukturalną obsługę wyjątków z skojarzonym filtrem lub przez obsługę C++ catch, w zależności, która wartość jest dynamicznie bliżej kontekstu wyjątku.Na przykład, poniższy program w języku C++ zgłasza wyjątek C wewnątrz C++ kontekstu try:

Przykład

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

Na przykład, poniższy kod instaluje niestandardową funkcje 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() );
    }
}
  

Klasa otoki dla wyjątków C

W prostym przykładzie jak wyżej, wyjątek C może być przechwycony tylko przez wielokropek (...) model obsługi catch.Brak informacji na temat typu lub rodzaju wyjątku jest przekazywany do modułu obsługi.Chociaż ta metoda zadziała, to w niektórych przypadkach, może być konieczne zdefiniowanie transformacji między dwoma modelami obsługi wyjątków tak, że każdy wyjątek C jest skojarzony z konkretną klasą.Aby to zrobić, można zdefiniować klasy "otoki" wyjątku w języku C, które mogą być używane lub dziedziczone w celu przypisania atrybutu typu określonej klasy wyjątku języka C.W ten sposób każdy wyjątek C może być obsługiwany przez moduł obsługi C++ catch bardziej niezależnie niż w poprzednim przykładzie.

Klasa otoki może mieć interfejs, składający się z niektórych elementów członkowskich funkcji, który określa wartość wyjątku i dostęp do rozszerzonych informacji kontekstu wyjątku dostarczonych przez model wyjątków C.Można także zdefiniować domyślny konstruktor i konstruktor, który akceptuje argument unsigned int (zapewnienie podstawowej reprezentacji wyjątku C) i konstruktor kopii bitowej.Możliwe implementacje klasy otoki wyjątku 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, należy zainstalować funkcję tłumaczenia niestandardowych wyjątków C, która jest wywoływana przez mechanizm obsługi wyjątków, każdorazowo, kiedy zgłaszany jest wyjątek w języku C.W ramach swojej funkcji tłumaczenia, możliwe jest zgłoszenie wyjątku dowolnego typu (może być to typ SE_Exception lub typ klasy pochodzący z SE_Exception), który może być wykryty przez odpowiednie modele obsługi C++ catch.Funkcja tłumaczenia może po prostu może nic nie zwracać, co oznacza, że nie obsłużyła wyjątku.Jeżeli sama funkcja tłumaczenia zgłasza wyjątek C, wywoływana jest funkcja terminate.

Aby określić niestandardową funkcję tłumaczenia, należy wywołać funkcje _set_se_translator z nazwą funkcji tłumaczenia, jako pojedynczy argument.Napisana funkcja tłumaczenia, jest wywoływana raz, dla każdego wywołania funkcji na stosie, który ma blok try.Domyślnie nie ma żadnych funkcji tłumaczenia; jeśli nie zostanie określona jedna poprzez wywołanie _set_se_translator, to wyjątek języka C można zastosować wyłącznie z wielokropkiem modelu obsługi catch.

Zobacz też

Informacje

Połączenie wyjątków języka C (strukturalnych) i C++