10
votes

bonne façon de stocker une exception dans une variable

J'ai une API qui présente des exceptions à l'intérieur des exceptions pour les rapports d'erreur. La structure de base est qu'elle a un objet d'exception racine qui hérite de std :: exception , alors il lancera une sous-classe de celle-ci.

Étant donné qu'une exception projetée dans une bibliothèque ou un fil et l'attraper dans une autre peut conduire à un comportement indéfini (au moins qt se plaint de cela et le désactive dans de nombreux contextes). J'aimerais envelopper les appels de bibliothèque dans des fonctions qui renvoient un code d'état et, si une exception s'est produite, une copie de l'objet d'exception.

Quelle est la meilleure façon de Store une exception (avec son comportement polymorphique) pour une utilisation ultérieure? Je crois que l'API future C ++ 0x utilise quelque chose comme ça. Alors quelle est la meilleure approche?

Le meilleur que je peux penser est d'avoir un clone () méthode dans chaque classe d'exception qui retournera un pointeur à une exception du même type. Mais ce n'est pas très générique et ne traite pas du tout des exceptions standard.

Toutes les pensées?

edit : il semble que c ++ 0x aura un mécanisme de ce . Il est décrit comme "magique de bibliothèque". Cela signifie-t-il que cela ne nécessite aucune des caractéristiques de la langue de C ++ 0x? Sinon, y a-t-il des implémentations compatibles avec C ++ 03?

edit : on dirait que Boost a un Mise en œuvre de la copie d'exception . Je vais garder la question ouverte pour tout boost :: copy_exception réponses.

EDIT : Pour adresser les préoccupations de J_Random_Hacker sur la cause première de l'exception étant une erreur de mémoire hors mémoire. Pour cette bibliothèque particulière et cette série d'exceptions, ce n'est pas le cas. Toutes les exceptions dérivées de l'objet d'exception racine représentent différents types d'erreurs d'analyse causées par une entrée d'utilisateur non valide. Les exceptions relatives à la mémoire provoqueront simplement un std :: Bad_alloc pour être jeté qui est adressé séparément.


0 commentaires

5 Réponses :


5
votes

Vous avez ce que vous seriez ce que je pense, c'est de votre mieux, seulement répondre. Vous ne pouvez pas conserver une référence à l'exception originale car elle va quitter la portée. Vous devez simplement en faire une copie et la seule façon générique de faire est avec une fonction prototype comme Clone ().

désolé.


4 commentaires

Mais méfiez-vous que la cause première de l'exception peut être une condition hors mémoire, auquel cas clone () échouera s'il tente d'appeler nouveau . Cela peut être venu, par ex. En surcharge Opérateur Nouveau () Pour chaque type d'exception à allouer à partir d'un tampon statique, mais ce n'est pas nécessairement assez non plus.


@J_Random_hacker: Eh bien, puisque nous obtenons Pedantic, ce que vous appelez hors de mémoire, c'est mieux appelé Bad-Alloc et qu'il ne doit pas nécessairement être réel de mémoire. Une autre raison de Bad-Alloc demande trop de mémoire et, dans ce cas, les petites allocations ultérieures vont réussir


@sbk: Est-ce vraiment pédant à considérer la possibilité de manquer de mémoire?


La réponse facile ici est de souligner qu'avec Bad_alloc, vous avez), et b) Obtenir une exception particulière que vous ne serez pas capable de clone car ce ne sera pas le vôtre.



1
votes

Vous êtes autorisé à jeter quoi que ce soit, y compris les pointeurs. Vous pouvez toujours faire quelque chose comme ceci: xxx

puis dans le gestionnaire d'exception stocker le pointeur capturé, qui sera entièrement polymorphe (ci-dessous en supposant que myException dérive de < code> std :: exception ): xxx

Il suffit de faire attention aux fuites de mémoire lorsque vous le faites de cette façon, c'est pourquoi La valeur et la référence à la référence sont normalement utilisées.

plus sur Catch-by-Pointer: http://www.parashift.com/c++-faq-lite/Exception.html#faq-17.8


4 commentaires

Le problème avec cette solution, car je vois que vous vusez peut-être une exception en raison de quelque chose qui a pour conséquence saine une condition hors mémoire, auquel cas nouveau échouera.


Cela a été mentionné dans le lien, mais vous pourriez dans la théorie de travailler autour de cela en ayant une exception préalablement allouée ou statique en mémoire de mémoire que vous lancez dans ce cas. Mais vous auriez alors besoin de vous assurer que vous ne supprimez pas cela comme vous le feriez vos autres exceptions. C'est difficile mais vous devez faire attention à beaucoup de pièges comme celui-ci.


Ne pouvions-nous pas vérifier si l'exception indique une condition de mémoire hors mémoire et simplement définir un int / booléen pour l'indiquer?


+1: Pour mon usage particulier, cela n'est pas une mauvaise idée. semblable à l'approche clone mais faisant au point de lancer.



0
votes

La raison pour laquelle attraper une exception projetée dans une bibliothèque et l'attraper dans une autre peut conduire à un comportement indéfini est que ces bibliothèques pourraient être liées à différentes bibliothèques d'exécution. Si vous retournerez une exception d'une fonction au lieu de le jeter, vous n'évitez pas ce problème.


1 commentaires

Je crois que vous êtes correct, je pense que la question Qt a avec elle est davantage de passer entre les threads (j'ai ajouté cette subtilité à ma question aussi).



0
votes

My Utility Library possède une classe AnyException de la même manière que boost :: n'importe quel sans le support de casting. Au lieu de cela, il possède un membre () qui jette l'objet d'origine stocké. XXX

Il s'agit d'une simplification, mais c'est le cadre de base. Mon code actuel désactive la copie et a plutôt déplacé la sémantique. Si nécessaire, vous pouvez ajouter une méthode virtuelle clone à la exceptebase assez facilement ... car exception connaît le type d'origine de l'objet, il peut transmettre la demande sur le constructeur de copie réelle et vous avez immédiatement un support pour tous les types copiables, pas seulement avec leurs propres clone méthode.

Quand cela a été conçu, c'était Non destiné à stocker des exceptions attrapées ... Une fois une exception, elle a été lancée, elle s'est propagée comme normale, les conditions hors de mémoire n'étaient pas envisagées. Cependant, j'imagine que vous pouvez ajouter une instance de std :: bad_alloc à l'objet et stockez-la directement dans ces situations. xxx

i Haven 't en fait testé ce deuxième bit du tout ... Je serais peut-être manquant quelque chose d'évident évident qui l'empêchera de travailler.


0 commentaires

9
votes

AS de C ++ 11, cela peut être fait avec STD :: Exception_Ptr.

(J'utilise cela dans une classe qui fait un STD :: filetage interruptible à condition que l'implémentation de thread sous-jacent est un thread de POSIX. Pour gérer des exceptions pouvant être lancées dans le code de l'utilisateur - qui provoque des problèmes si elles sont lancées dans une certaine section critique de ma mise en œuvre - je stocke l'exception en utilisant STD :: Exceptionnel_ptr, puis la jetez plus tard une fois la section critique terminée.) P>

Pour stocker l'exception, vous l'attrapez et stockez-le dans le PTR Variable. P>

try {
    if (eptr) {
        std::rethrow_exception(eptr);
    }
} catch (const std::exception& e) {
    ... examine e ...
} catch (...) {
    ... handle any non-standard exceptions ...
}


0 commentaires