Partager via


Gérer les exceptions structurées en C++

La principale différence entre la gestion des exceptions structurées C (SEH) et la gestion des exceptions C++ est que le modèle de gestion des exceptions C++ traite des types, tandis que le modèle de gestion des exceptions structurées C traite des exceptions d’un type ; spécifiquement, unsigned int. Autrement dit, les exceptions C sont identifiées par une valeur entière non signée, tandis que les exceptions C++ sont identifiées par type de données. Lorsqu’une exception structurée est déclenchée en C, chaque gestionnaire possible exécute un filtre qui examine le contexte d’exception C et détermine s’il faut accepter l’exception, le transmettre à un autre gestionnaire ou l’ignorer. Lorsqu'une exception est levée en C++, elle peut être de n'importe quelle type.

Une deuxième différence est que le modèle de gestion des exceptions structurées C est appelé asynchrone, car les exceptions se produisent secondaires au flux normal du contrôle. Le mécanisme de gestion des exceptions C++ est entièrement synchrone, ce qui signifie que les exceptions se produisent uniquement lorsqu’elles sont levées.

Lorsque vous utilisez l’option de compilateur /EHs ou /EHsc , aucun gestionnaire d’exceptions C++ ne gère les exceptions structurées. Ces exceptions sont gérées uniquement par __except des gestionnaires d’exceptions structurées ou __finally des gestionnaires de terminaison structurés. Pour plus d’informations, consultez Gestion des exceptions structurées (C/C++).

Sous l’option du compilateur /EHa , si une exception C est déclenchée dans un programme C++, elle peut être gérée par un gestionnaire d’exceptions structurées avec son filtre associé ou par un gestionnaire C++ catch , selon ce qui est dynamiquement plus proche du contexte d’exception. Par exemple, cet exemple de programme C++ déclenche une exception C dans un contexte C++ try :

Exemple : intercepter une exception C dans un bloc catch 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.

Classes wrapper d’exception C

Dans un exemple simple comme ci-dessus, l’exception C peut être interceptée uniquement par un gestionnaire de points de suspension (...). catch Aucune information sur le type ou la nature de l'exception n'est communiquée au gestionnaire. Bien que cette méthode fonctionne, dans certains cas, vous pouvez définir une transformation entre les deux modèles de gestion des exceptions afin que chaque exception C soit associée à une classe spécifique. Pour en transformer un, vous pouvez définir une classe « wrapper » d’exception C, qui peut être utilisée ou dérivée afin d’attribuer un type de classe spécifique à une exception C. En procédant ainsi, chaque exception C peut être gérée séparément par un gestionnaire C++ catch spécifique, au lieu de toutes ces exceptions dans un seul gestionnaire.

Votre classe wrapper peut avoir une interface constituée de certaines fonctions membres qui déterminent la valeur de l'exception et qui accèdent aux informations de contexte d'exception étendues fournies par le modèle d'exception C. Vous pouvez également définir un constructeur par défaut et un constructeur qui accepte un unsigned int argument (pour fournir la représentation d’exception C sous-jacente) et un constructeur de copie au niveau du bit. Voici une implémentation possible d’une classe wrapper d’exception 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;
   }
};

Pour utiliser cette classe, installez une fonction de traduction d’exception C personnalisée appelée par le mécanisme de gestion des exceptions internes chaque fois qu’une exception C est levée. Dans votre fonction de traduction, vous pouvez lever n’importe quelle exception typée (peut-être un SE_Exception type ou un type de classe dérivé de SE_Exception) qui peut être interceptée par un gestionnaire C++ catch correspondant approprié. La fonction de traduction peut retourner à la place, ce qui indique qu’elle n’a pas géré l’exception. Si la fonction de traduction elle-même déclenche une exception C, l’arrêt est appelé.

Pour spécifier une fonction de traduction personnalisée, appelez la fonction _set_se_translator avec le nom de votre fonction de traduction comme argument unique. La fonction de traduction que vous écrivez est appelée une seule fois pour chaque appel de fonction sur la pile qui a try des blocs. Il n’existe aucune fonction de traduction par défaut ; si vous n’en spécifiez pas un en appelant _set_se_translator, l’exception C ne peut être interceptée que par un gestionnaire de points de suspensioncatch.

Exemple : utiliser une fonction de traduction personnalisée

Par exemple, le code suivant installe une fonction de traduction personnalisée, puis lève une exception C qui est encapsulée par la classe 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

Voir aussi

Mélange d’exceptions C (structurées) et C++