11
votes

Exceptions à l'intérieur des exceptions en C ++

Lorsque vous travaillez avec C # ou Java, j'ai utilisé des classes d'exception qui comprenaient d'autres exceptions comme membres de la classe. Par exemple:

 try {
     // Code that throws an exception of type MyException
 } catch(MyException ex) {
     MyException another = new MyException();
     another.setEx(ex);
     another.setMessage("A message that explains where the other exception was caught and on what conditions");

     throw another;
 }


10 commentaires

Vous ne pouvez pas avoir plusieurs exceptions à C ++. Si une nouvelle exception est lancée avant que l'exception actuelle soit capturée, le programme est terminé (plus précisément std :: terminer est appelé)


@Gene: Il s'agit d'une variation de Rethrow, où l'exception existante est bourrée à l'intérieur d'une nouvelle exception. Probablement pas réalisable sans collection de déchets.


@Ben Voigt: probablement réalisable sans collection de déchets s'il n'était pas si difficile de se rappeler exactement lorsque des exceptions font appel à leurs destructeurs.


@Dietrich: C'est la difficulté.


@Benvoight GC est un hareng rouge. Le clonage fonctionne aussi et est disponible avec C ++ 0x.


@LUC: Vous ne pouvez pas cloner une exception arbitraire.


@Benvoigt Eh bien, std :: actuel_exception ne garantit pas le clonage, mais cela ne l'interdit pas. En tout cas, c'est assez bon pour le travail.


@LUC: Notez que toutes ces options sont beaucoup plus compliquées que la méthode lorsque GC est disponible, auquel cas vous venez de lancer un pointeur sur une exception gérée par GC de tout type.


@Benvoigt GC Pas beaucoup plus compliqué que la solution de bibliothèque de Boost.Exception :)? Cela donne un sens si le collecteur vient gratuitement avec votre runtime Oui, mais je ne serais pas brancher un collecteur pour que je puisse obtenir des exceptions imbriquées.


@LUC: À droite, la question posée si C ++ peut le faire de la même manière C # et Java le faire, et les deux d'entre eux ont omniprésent et l'utilisent pour prolonger la durée de vie d'une exception capturée.


3 Réponses :


0
votes

Je ne pense pas que nous avons besoin d'une propriété d'instance de classe (c'est-à-dire EX ) dans Java / C # / C ++ si votre classe n'est pas conçue dans le modèle Singleton. En outre, ici est un didacticiel que vous voudrez peut-être prendre un regarder.


2 commentaires

Le membre myException est utilisé comme suit: 1. J'atteigne l'exception lancée 2. J'instéenne une autre exception avec un message plus spécifique et définissez le ex Propriété à l'exception capturée dans 1 3. Lancez la nouvelle exception créée. C'est un bon tutoriel cependant, celui que tu m'as envoyé.


On dirait que tu voulais le garder pour la référence arrière, non? Pourquoi n'est-ce pas une exception une instance alors? En outre, si vous voulez seulement une référence arrière pour garder l'exception originale, pourquoi ne pas simplement empiler les messages de trace et jeter l'exception originale? Probablement dans le constructeur? Ça me ressemble plus de raisons. Mes 2 cents



22
votes

Il n'y a pas de moyen correct de le faire avec les exceptions standard en C ++ 03 car elles sont conçues pour être utilisées polymorphiquement mais ne peuvent pas être clonées. Donc, si vous attrapez std :: exception const & e code> vous pouvez em> stocker une copie, mais cela conduira à la tranchée, perdant toutes les informations utiles. Vous devriez pas strud> Stocker un pointeur ou une référence à l'exception, car sa vie se terminera dès que la clause code> Catch code> (en supposant que vous n'émettez pas d'exception originale. ).

Vous pouvez vous contourner cette limitation si vous connaissiez chacun chaque type pouvant être lancé et les tester tout sauf que ce n'est pas un design agréable (c'est-à-dire qu'il subvertit le polymorphisme). Il est plus logique d'écrire une classe d'exception de base qui peut être clonée et attraper cela. Vous avez toujours le problème si vous attrapez un std :: exception code> qui venait du code de quelqu'un d'autre cependant. P>

à ce stade, je me sens obligé de mentionner Boost.Exception . Il est facile d'écrire votre propre hiérarchie d'exception et fournit divers utilitaires, parmi lesquels boost :: exception_ptr code>. Vous pouvez ensuite faire: p> xxx pré>

ceci est si utile que boost :: diagnostic_info code> prend en charge et affichera l'exception imbriquée pour vous (c'est sans papiers) . Il a même été suggéré que ce néd_exception code> Typedef code> devrait également faire partie de la bibliothèque. En attendant, il est facile de l'écrire vous-même. P>

Ne vous attendez pas à la magie cependant: boost :: actuel_exception code> "capture" l'exception active (imprimé fin: ou un clone de celui-ci ) Bien seulement si le site de lancer utilisé boost :: activer_current_exception code>. (Fonctionnel, il s'agit de l'équivalent moral d'utiliser une classe d'exception de base qui peut être clonée). Si ce n'est pas le cas, cela ne manquera pas, mais certaines informations peuvent être perdues. P>


En tant que note finale, sachez que la conception de Boost.Exception a été adoptée pour C ++ 0x. Ainsi, les points suivants stockent correctement l'exception active, sans aucun des Boost :: courant_exception code> car il dispose d'un support linguistique: p>

catch(...) {
    // throws an unspecified type derived from your_exception_type
    // and std::nested_exception
    std::throw_with_nested(your_exception_type());
}


1 commentaires

Merci pour la tête, C ++ 0x continue de me surprendre :)



1
votes

Je suppose que vous pouvez lancer un unique_ptr , puis faire inner_exception autre unique_ptr qui prend la propriété.


4 commentaires

Et vous devez vous assurer que seuls les pointeurs vers la même classe de base sont lancés car cela ne se comporte pas de manière polymorphique.


@LUC: C'est certainement un inconvénient, n'est-ce pas?


Eh bien, étant donné que std :: unique_ptr est C ++ 0x, je pense qu'il y a de meilleures alternatives.


@LUC: std :: unique_ptr est C ++ 0x, mais il existe de nombreuses implémentations CODE_PTR dans C ++ 03, sous ces noms tels que Boost :: scoped_ptr .