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: p>
fonction 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. P> A code> appels
b code> qui à tour appelle
c code>. Une exception est lancée à partir de
C code> et le bloc de capture pour cette exception est dans
A code>. Qu'advient-il des ressources acquises dans
B code> avant l'appel sur
C code>? 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. P>
7 Réponses :
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. P>
Le langage de programmation D est en réalité en standard. P>
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. P>
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. P>
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. P>
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. P>
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.
c ++ ne prend pas en charge enfin fort> pour la gestion de choses de dernière minute à la fin du bloc. Que va-t-il se passer est que lorsque la fonction 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 fort> (avec des pointeurs ou autre), il s'agit donc d'une mauvaise conception de code, et ils ne seront pas libérés. P> Si vous savez dans B strong> qu'il pourrait y avoir une exception dans Le plus proche que vous peut arriver à un bloc si vous souhaitez fonctionner exactement comme un pour vous tous qui ont un problème avec un peu plus sur goto p> p>
Ensuite, le programme reviendra au code dans enfin code> utilise
attrape (...) code> 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 code> p>
enfin code> Block que vous pouvez faire: p>
goto code> ... il est toujours une commande et c'est un exemple parfait que non
code> ou
Continuer code> ou une fonction en ligne peut remplacer
goto code>. p>
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 code>,
en utilisant code> et
différer code> 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.
Un extrait de ma page d'accueil abandonnée ... p>
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. P>
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. p> blockQuote>
... p>
(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. P> blockQuote>
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? P> blockQuote>
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 em> strong> ( nouveau code>,
dynamic_cast < / Code>) Et, bien sûr, tout logiciel tiers que vous utilisez peut-être pourrait bien. p>
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 em> strong>, vous feriez donc mieux de commencer à traiter avec eux dès que possible. p>
Soyez heureux que vous ayez des exceptions. Considérez ce qui se passe avec les codes de retour d'erreur dans votre exemple. Fonction 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) p> c code> renvoie un code d'erreur.
B code>, étant naïf comme il l'avale. Appelant
A code>, qui serait capable de la manipuler, n'est même pas informé de l'erreur. P>
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.