Détermination du type d’exception après la capture de l’exception?

Existe-t-il un moyen de déterminer le type d’exception, même si vous savez que vous avez capturé l’exception avec un catch all?

Exemple:

try { SomeBigFunction(); } catch(...) { //Determine exception type here } 

Vous pouvez effectivement déterminer le type dans une capture (…), mais ce n’est pas très utile:

 #include  #include  class E1 : public std::exception {}; class E2 : public std::exception {}; int main() { try { throw E2(); } catch( ... ) { try { throw; } catch( const E1 & e ) { std::cout << "E1\n"; } catch( const E2 & e ) { std::cout << "E2\n"; } } } 

Réponse courte: Non.

Longue réponse:

Si vous dérivez toutes vos exceptions à partir d’un type de base commun (par exemple, std :: exception) et que vous interceptez cela explicitement, vous pouvez l’utiliser pour obtenir des informations de type à partir de votre exception.

Mais vous devriez utiliser la fonctionnalité catch pour capturer comme type d’exception spécifique, puis travailler à partir de là.

La seule utilisation réelle de catch (…) est:

  • Catch: et jeter une exception (stop exception destructor echappant).
  • Capture: enregistre une exception inconnue et la relance.

Modifié: Vous pouvez extraire les informations de type via dynamic_cast <> () ou via typid (). Toutefois, comme indiqué ci-dessus, ce n’est pas quelque chose que je recommande. Utilisez les déclarations de cas.

 #include  #include  class X: public std::runtime_error // I use runtime_error a lot { // its derived from std::exception public: // And has an implementation of what() X(std::ssortingng const& msg): runtime_error(msg) {} }; int main() { try { throw X("Test"); } catch(std::exception const& e) { std::cout << "Message: " << e.what() << "\n"; /* * Note this is platform/compiler specific * Your milage may very */ std::cout << "Type: " << typeid(e).name() << "\n"; } } 

Si vous devez gérer les exceptions différemment en fonction de ce qu’elles sont, vous devriez intercepter des exceptions spécifiques. S’il existe des groupes d’exceptions qui doivent tous être gérés de manière identique, il est préférable de les dériver d’une classe de base commune et de capturer la classe de base. Tirez parti du pouvoir et des paradigmes de la langue, ne vous battez pas contre eux!

Il n’y a pas de méthode standard et portable pour le faire. Voici un moyen non portable de le faire sur GCC et Clang

 #include  #include  const char* currentExceptionTypeName() { int status; return abi::__cxa_demangle(abi::__cxa_current_exception_type()->name(), 0, 0, &status); } int main() { try { throw std::ssortingng(); } catch (...) { std::cout<<"Type of caught exception is "< 

Sortie:

 Type of caught exception is std::__cxx11::basic_ssortingng, std::allocator > 

Non.

Cela exigerait à tout le moins que vous puissiez accéder à l’exception actuelle. Je ne crois pas qu’il existe un moyen standard de le faire.

Une fois que vous avez eu l’instance d’exception, vous devrez utiliser un algorithme d’inspection de type. C ++ n’a pas de support inhérent à cela. Au mieux, vous devriez avoir une grosse déclaration if / elseif avec dynamic_cast pour vérifier le type.

J’ai essayé de différentes manières. cela fonctionne pour moi:

Commencez par sous- classer runtime_error :

 /*----------------------------------------------------------------------*/ /* subclass runtime_error for safe exceptions in try/throw/catch */ #include  /* a little preprocessor magic here -- makes a subclass of runtime_error*/ #define NEWERROR( NE ) class NE : public runtime_error { \ public: NE ( ssortingng const& error ) : runtime_error(error) {} } NEWERROR( FileError ); NEWERROR( NetworkError ); NEWERROR( SsortingngError ); NEWERROR( CofeeError ); /*----------------------------------------------------------------------*/ 

Ensuite, vous pouvez créer certaines instances de vos exceptions.

 /*----------------------------------------------------------------------*/ /* some example pre-defined exceptions */ FileError ReadOnly ( "ReadOnly" ); FileError FileNotFound ( "FileNotFound" ); NetworkError TimeOutExceeded ( "TimeOutExceeded" ); NetworkError HostNotFound ( "HostNotFound" ); CoffeeError OutOfCoffee ( "OutOfCoffee" ); /*----------------------------------------------------------------------*/ 

Informez explicitement le compilateur que votre fonction peut générer une exception ou que le programme se terminera probablement au moment de son lancement. Des données risquent donc d’être perdues ou corrompues si des ressources sont en cours d’utilisation.

“Assurez-vous de pouvoir attraper tout ce que vous pouvez lancer.”

(J’utilise le terme générique runtime_error car son lancement et sa capture couvrent toutes mes exceptions, ainsi que celles des systèmes.)

 /*----------------------------------------------------------------------*/ /* example function that may throw an exception */ #include  ifstream& getFileStream (ssortingng fname) throw (runtime_error) { if ( fname == "" ) throw SsortingngError( " fname:empty ssortingng" ); // processing stops here if thrown try { ifstream Inputfstream; ifstream& ifsref = Inputfstream; // ifstream has its own  exception // mechanisms and procedures ifsref.exceptions ( ifstream::failbit | ifstream::badbit ); ifsref.open (fname , ifstream::in); // could fail ==> ifstream::failure exception } catch (ifstream::failure e) { throw FileError( fname + ssortingng(e.what() ) ); } return ifsref; } /*----------------------------------------------------------------------*/ 

alors dans votre try / catch

 /*----------------------------------------------------------------------*/ catch (FileNotFound fnf) //catch a specific error { if (DEBUG) cerr << "[File Not Found Error: " << fnf.what() << "]" << endl; ... (handle it) ... } catch (FileError fe) //catch a specific type { if (DEBUG) cerr << "[File Error: " << fe.what() << "]" << endl; ... (handle it) ... } catch (runtime_error re ) // catch a generic type { if (DEBUG) cerr << "[Runtime error: " << re.what() << "]" << endl; // determine type by string comparison if ( re.what() == string("ResourceNotavailable") ) ... if ( re.what() == string("NetWorkError") ) ... ... } catch ( ... ) // catch everything else { ... exit, rethrow, or ignore ... } /*----------------------------------------------------------------------*/ 

La classe runtime-error est bien supscope dans les bibliothèques standard c ++. Les compilateurs le savent en interne et savent comment optimiser la mémoire et la répartition afin que vous puissiez les utiliser sur différentes bases de code, en toute sécurité et en toute confiance. Le code est portable et compatible avec de nombreux compilateurs et architectures.

Il peut être préférable et plus rapide d'attraper chaque erreur séparément dans une clause catch, de plus spécifique à plus générique, si vous pensez qu'une série de correspondances de chaînes est un gaspillage considérable de ressources processeur et de mémoire (le compilateur les optimise cependant).

vous donne plusieurs types d'exceptions dans 2 groupes:

  • Erreurs de logique:

     logic_error domain_error invalid_argument length_error out_of_range 
  • Erreurs d'exécution:

     runtime_error range_error overflow_error underflow_error 

la syntaxe d'utilisation est légèrement différente pour certains d'entre eux.

Selon Sagesse conventionnelle en C ++, vos exceptions doivent être relativement "plates", ce qui signifie que les grandes hiérarchies de catégories spécifiques d’exceptions doivent être évitées au profit de définitions génériques courtes mais informatives pour les tâches de programmation générales. Les tâches spécifiques à un domaine, telles que la logique du système réseau, les calculs avancés, etc., peuvent tirer parti de la spécificité, mais peuvent être facilement réalisées en créant des chaînes d'erreur intelligentes avec des exceptions génériques d'exécution et de logique.

Enfin, mon point est le suivant : vous pouvez réaliser tout cela en lançant et en capturant uniquement runtime_error .

Il n'est pas nécessaire de créer toute une panoplie d'exceptions très spécifiques (comme Java) pour chaque classe, chacune gérant une erreur spécifique.

Cette question a été posée il y a quelque temps et je propose cette réponse pour accompagner la réponse acceptée d’il y a 9 ans. Je suis d’accord avec l’intimé pour dire que cette réponse, “… n’est pas très utile”. En outre, cela ouvre la porte à une exception qui avait été gérée autrefois. Pour illustrer mon propos, permettez-moi de développer la réponse de l’intimé

 #include  #include  class E1 : public std::exception {}; class E2 : public std::exception {}; class E3 : public std::exception {}; int main() { try { throw E3(); } catch( ... ) { try { // OOOPS!!! E3 is now unhandled!!!!!! throw; } catch( const E1 & e ) { std::cout << "E1\n"; } catch( const E2 & e ) { std::cout << "E2\n"; } } } 

Une alternative à cette approche serait la suivante:

 #include  #include  class E1 : public std::exception {}; class E2 : public std::exception {}; class E3 : public std::exception {}; int main() { try { throw E3(); } catch( const E1 & e ) { std::cout << "E1\n"; } catch( const E2 & e ) { std::cout << "E2\n"; } catch( ... ) { std::cout << "Catch-all..."; } } 

Cette seconde approche semble être équivalente à la première et présente l’avantage de traiter spécifiquement E1 et E2 et de capturer tout le rest. Ceci est offert seulement comme alternative.

Veuillez noter que, selon le projet C ++ du 2011-02-28, paragraphe 15.3, puce 5, " S'il est présent, un gestionnaire ... doit être le dernier gestionnaire de son bloc try. "

à condition que c ++ 11 disponible,

 bool throwing_func() { // something is wrong... throw char('5'); // ... return true; } void exception_handler(std::exception_ptr _Eptr) { try { if (_Eptr) {std::rethrow_exception(_Eptr);} } catch(int _Xi) { std::cout << "int\n"; } catch(char _Xc) { std::cout << "char\n"; } catch(const std::exception& _Xe) { std::cout << "std::exception " << _Xe.what() << "\n"; } catch (...) {// develop more catch cases above to avoid what follows std::cout << "unhandled exception\n"; // grande problema } } int main() { try { throwing_func(); } catch(...) { //Determine exception type here exception_handler(std::current_exception()); } return 0; } 

Si vous utilisez Visual C ++ (géré), vous pouvez utiliser la méthode GetType () pour obtenir le type d’exception et le gérer à partir de là.

Par exemple

 try { // Run the application Application::Run(mainForm); } catch (Exception^ e) { Ssortingng^ exception_type = e->GetType()->ToSsortingng(); throw; } 

La chaîne contiendra quelque chose comme “System.ArgumentOutOfRangeException”.