Voici un exemple de ce que je fais souvent lorsque je souhaite ajouter des informations à une exception:
std::stringstream errMsg;
errMsg << "Could not load config file '" << configfile << "'";
throw std::exception(errMsg.str().c_str());
Y a-t-il une meilleure façon de le faire?
std∷exception
fait de ne pas avoir de constructeur avecchar*
arg.std::string
a un constructeur implicite qui prend unconst char*
...std::exception
classes enfants de MS , et est utilisé par leurs versions destd::runtime_error
etstd::logic_error
. En dehors de ceux définis par la norme, la version de MSVS<exception>
comprend également deux autres constructeurs, l'un prenant(const char * const &)
et l'autre prenant(const char * const &, int)
. Ils sont utilisés pour définir une variable privée,const char * _Mywhat
; if_Mywhat != nullptr
, puis lewhat()
renvoie par défaut. Le code qui en dépend n'est probablement pas portable.Réponses:
Voici ma solution:
Exemple:
la source
Les exceptions standard peuvent être construites à partir d'un
std::string
:Notez que la classe de base ne
std::exception
peut pas être construite ainsi; vous devez utiliser l'une des classes dérivées concrètes.la source
Il existe différentes exceptions comme
runtime_error
,range_error
,overflow_error
,logic_error
, etc .. Vous devez passer la chaîne dans son constructeur, et vous pouvez concaténer tout ce que vous voulez à votre message. C'est juste une opération de chaîne.Vous pouvez également utiliser
boost::format
comme ceci:la source
La classe suivante peut être très utile:
Exemple d'utilisation:
la source
throw std::runtime_error(sprintf("Could not load config file '%s'", configfile.c_str()))
throw std::runtime_error("Could not load config file " + configfile);
(conversion de l'un ou l'autre argument enstd::string
si nécessaire).printf
et les amis sont imminents dans C ++ 11. Un tampon de taille fixe est à la fois une bénédiction et une malédiction: il n'échoue pas dans les situations de faibles ressources mais peut tronquer le message. Je considère que la troncature d'un message d'erreur est une meilleure option que l'échec. En outre, la commodité des chaînes de format a été prouvée par de nombreux langages différents. Mais vous avez raison, c'est en grande partie une question de goût.Utilisez l'opérateur littéral de chaîne si C ++ 14 (
operator ""s
)ou définissez le vôtre si en C ++ 11. Par exemple
Votre déclaration de lancer ressemblera alors à ceci
qui a l'air bien et propre.
la source
Une manière vraiment plus agréable serait de créer une classe (ou des classes) pour les exceptions.
Quelque chose comme:
La raison en est que les exceptions sont bien plus préférables que le simple transfert d'une chaîne. En fournissant différentes classes pour les erreurs, vous donnez aux développeurs une chance de gérer une erreur particulière d'une manière correspondante (pas seulement d'afficher un message d'erreur). Les personnes qui interceptent votre exception peuvent être aussi spécifiques qu'elles en ont besoin si vous utilisez une hiérarchie.
a) On peut avoir besoin de connaître la raison spécifique
a) un autre ne veut pas connaître les détails
Vous pouvez trouver de l'inspiration sur ce sujet dans https://books.google.ru/books?id=6tjfmnKhT24C Chapitre 9
En outre, vous pouvez fournir un message personnalisé aussi, mais attention - il n'est pas sûr de composer un message soit avec
std::string
oustd::stringstream
ou tout autre moyen qui peut provoquer une exception .Généralement, il n'y a aucune différence que vous allouiez de la mémoire (travaillez avec des chaînes de manière C ++) dans le constructeur de l'exception ou juste avant de lancer - l'
std::bad_alloc
exception peut être levée avant celle que vous voulez vraiment.Ainsi, un tampon alloué sur la pile (comme dans la réponse de Maxim) est un moyen plus sûr.
Cela est très bien expliqué sur http://www.boost.org/community/error_handling.html
Ainsi, la meilleure façon serait un type spécifique d'exception et d'éviter de composer la chaîne formatée (au moins lors du lancement).
la source
Ran dans un problème similaire, en ce que la création de messages d'erreur personnalisés pour mes exceptions personnalisées rend le code laid. C'était ma solution:
Cela sépare la logique de création des messages. J'avais initialement pensé à remplacer what (), mais vous devez ensuite capturer votre message quelque part. std :: runtime_error a déjà un tampon interne.
la source
Peut être ça?
Il crée un ostringstream temporaire, appelle les opérateurs << si nécessaire, puis vous mettez cela entre crochets et appelez la fonction .str () sur le résultat évalué (qui est un ostringstream) pour passer un std :: string temporaire au constructeur de runtime_error.
Remarque: l'ostringstream et la chaîne sont des temporaires de valeur r et sortent donc de la portée après la fin de cette ligne. Le constructeur de votre objet d'exception DOIT prendre la chaîne d'entrée en utilisant la sémantique copy ou (meilleure) move.
Supplémentaire: je ne considère pas nécessairement cette approche comme une «meilleure pratique», mais elle fonctionne et peut être utilisée à la rigueur. L'un des plus gros problèmes est que cette méthode nécessite des allocations de tas et que l'opérateur << peut lancer. Vous ne voulez probablement pas que cela se produise; Cependant, si vous entrez dans cet état, vous aurez probablement beaucoup plus de problèmes à craindre!
la source