8
votes

Objection aux exceptions

Un de mes amis m'a soulevé ce problème. J'étais coincé parce que je ne suis pas habile à utiliser des exceptions. N'oubliez pas que nous travaillons tous les deux dans un environnement de travail où nous utilisons C ++ mais que nous utilisons des erreurs de traitement dans la tradition C. Son problème était quelque chose comme ceci:

fonction A appels b qui à tour appelle c . Une exception est lancée à partir de C et le bloc de capture pour cette exception est dans A . Qu'advient-il des ressources acquises dans B avant l'appel sur C ? Comment pouvons-nous les nettoyer? Ma réponse a été utilisée Raii. Mais même quand je l'ai dit, je savais que ça ne va pas marcher. Nous avons d'énormes bases de code qui ont été écrites en mode C. Nulle part dans le code n'ai-je vu des pointeurs automatiques et tels. Les ressources ne sont pas nécessairement enveloppées dans des classes. Même quand ils sont, les destructeurs sont laissés pour le compilateur dans la plupart des cas. En bref, tout est fait manuellement.

Le problème réel est ce qu'il faut faire pour rendre la transition de C d'erreur de traitement des erreurs à des exceptions avec le poids d'une base de code énorme? Le problème que mon ami a demandé n'est que l'une des questions possibles pouvant être soulevées lorsque vous avez les pieds à la base de la gestion des erreurs C et que vous voulez savoir comment la migration de là sur des exceptions peut se produire.


3 commentaires

Si je comprends bien, vous avez écrit le code C-Classes, de sorte que ce n'est pas une exception en toute exception, essayons de le transformer en code C ++ plus idiomatique? Et votre question est de savoir comment faciliter cette transition?


C'était plus une question oui ou non.


@Gman: Oh désolé :). Oui.


7 Réponses :


5
votes

Il y a une technique développée par Andrei Alexandrescu et Joshua Lehrer appelée Guard de la portée qui fournit une technique pour fournir un code de «sortie de portée» dès que vous allouez un objet et d'ouvrir la portée à ce stade.

Le langage de programmation D est en réalité en standard.

Boost Bibliothèques a une amélioration de celle-ci appelée Étude de portée . Si votre code n'est pas sûr de l'exception, car la fonction B ne semble pas être, elle ne se chargera pas correctement si quelque chose lance.

Destructeurs s'exécuteront lors du déroulement de la pile d'appels après une exception. C'est pourquoi vous devez vous assurer qu'ils ne jettent pas eux-mêmes aucune exception.


0 commentaires

1
votes

Vous devez de toute façon migrer vers Raii, car vous ne pouvez pas faire des erreurs lorsque vous modifiez le flux de contrôle, entre autres choses. Vous devez mettre à niveau. Des exceptions signifient que vous ne pouvez pas mettre à jour une fonction de mise à niveau à moitié, qui peut en avoir une exception.


0 commentaires

0
votes

Votre ami est parfaitement correct, et c'est l'une des raisons pour lesquelles Google n'utilise pas d'exceptions en interne. Voir http://google-styleguide.googlecode.com/svn/trunk/ cppguide.xml # exceptions (et ouvrez la petite flèche) pour leur explication de la question.


4 commentaires

Garder à l'esprit leur raisonnement est "Nous avons un mauvais code, par rapport aux normes modernes, nous n'utiliserons donc pas les caractéristiques de langue moderne"; C'est-à-dire que vous n'utilisez pas cela pour de nouveaux projets.


@Gman: Je pense qu'ils admettent que lorsqu'ils disent, "les choses seraient probablement différentes si nous devions tout faire à partir de zéro." Cependant, le raisonnement est très applicable à la situation de l'OP.


Mais contrairement à Google, l'OP semble être disposé à migrer son code pour devenir meilleur et demande comment le faire.


@Fabio Fracassi: Le problème est qu'il n'y a pas de bon chemin d'où il se trouve là où il veut être.



1
votes

c ++ ne prend pas en charge enfin pour la gestion de choses de dernière minute à la fin du bloc.

Que va-t-il se passer est que lorsque la fonction C jette une exception, retourne de la fonction. Ce qui signifie que toutes les variables locales seront détruites.
Ensuite, le programme reviendra au code dans B , il vérifiera un bloc de capture, voir qu'il n'y a pas non plus et sautera à la fonction A. Encore une fois, toutes les variables locales de B seront libérées.

Vous devez vous rappeler que vous travaillez en C ++ ... vous devez gérer vos objets. Donc, si vous avez des objets, vous vous demandez simplement de librement dans B (avec des pointeurs ou autre), il s'agit donc d'une mauvaise conception de code, et ils ne seront pas libérés.

Si vous savez dans B qu'il pourrait y avoir une exception dans C , vous pouvez simplement mettre une attrape là-bas, puis jeter l'exception capturée.

Le plus proche que vous peut arriver à un bloc enfin utilise attrape (...) et utilisez-le pour libérer la mémoire ... mais il ne sera entré qu'en réalité une exception si Ce n'est pas identique à enfin xxx

si vous souhaitez fonctionner exactement comme un enfin Block que vous pouvez faire: xxx

pour vous tous qui ont un problème avec goto ... il est toujours une commande et c'est un exemple parfait que non ou Continuer ou une fonction en ligne peut remplacer goto .

un peu plus sur goto


3 commentaires

En fait, je considère que goto est une commande toujours en C pour exactement cet objectif, c'est-à-dire une manipulation "nettoyage". Dans C ++, les destructeurs le feront pour vous et avec la portée de la portée / sortie, vous pouvez écrire votre code «Quitter» au point de répartition.


J'ai considéré enfin , en utilisant et différer les outils manifestants pour émuler C ++ Raii. Avec Raii, vous écrivez la classe et il est toujours utilisé correctement, avec les autres, chaque appel doit être soigneusement emballé: /


ScopeGuard est beaucoup supérieure: beaucoup plus propre, plus facile à moquer de la raison et moins un non-équoncés goto.



0
votes

Un extrait de ma page d'accueil abandonnée ...

sans répéter dans le détail tout problèmes inhérents à exception Manipulation (1) Je veux remarquer que le idée principale: la partie complexe n'est pas Où l'exception est générée (lancer) ou où l'exception est manipulé (capture) mais dans les méthodes de toutes les classes L'exception passe à travers presque asynchrone pendant le processus de déruisement des piles.

Payer une attention particulière sur la façon dont les méthodes sont écrits sont relativement faciles à éviter Perdre des ressources en cas d'exception (Utilisation de Auto_PTR et de classes similaires) Mais les choses sont beaucoup plus complexes quand on prend en compte l'état logique de l'objet ou d'autres objets manipulé avant le lancer. Dans le Signification la plus stricte d'exception-coffre-fort une méthode devrait réussir ou être un non-op: En d'autres termes, le état logique de l'objet appelé (et d'autres objets concernés) devraient être le même si une exception est lancée: non la différence devrait être visible à travers l'interface publique de toutes impliquées classes.

...

(1) pour une description étendue, lisez le Article "Manipulation d'exception: un faux Sens de la sécurité "de Tom Cargill Disponible Online ou l'intéressant Collection de problèmes / solutions qui Cet article généré sur Usenet Disponible sur le livre "Exceptionnel C ++ "par SATANTER HERB Isbn = 0-201-61562-2.


0 commentaires

2
votes

Le problème réel est ce qu'il faut faire pour effectuer la transition de C manipulation des erreurs à des exceptions avec le poids d'une base de code énorme?

Non, le vrai problème est que, puisque vous programmez en C ++, vous devriez avoir depuis longtemps avec ceci. Même si votre propre code ne propose pas d'exceptions, certains code dans la bibliothèque standard et le système d'exécution peuvent lancer ( nouveau , dynamic_cast < / Code>) Et, bien sûr, tout logiciel tiers que vous utilisez peut-être pourrait bien.

Je conviens que le gardien de la portée est probablement votre meilleur pari pour ajouter une exception-sécurité comme une réflexion après coup. Cependant, ne vous trompez pas en pensant que vous n'avez pas besoin de le faire tant que vous ne jetez pas vous-même des exceptions. Vous utilisez une langue avec des exceptions , vous feriez donc mieux de commencer à traiter avec eux dès que possible.


0 commentaires

0
votes

Soyez heureux que vous ayez des exceptions. Considérez ce qui se passe avec les codes de retour d'erreur dans votre exemple. Fonction c renvoie un code d'erreur. B , étant naïf comme il l'avale. Appelant A , qui serait capable de la manipuler, n'est même pas informé de l'erreur.

Votre meilleur pari est d'aller de C droit à C ++ 0x. Il offre une nouvelle fonctionnalité, Lambda. Ce sont des fonctions anonymes, définies dans d'autres fonctions. Vous pouvez mettre votre code de nettoyage C sur là et l'avoir appelé par un objet "Scendeurguard". exemple (je sauterais la macro)


0 commentaires