La Boucle Infinie Qui En Fait N’Est Exécutée Qu’Une Fois
Par Emmanuel Deloget, vendredi 3 novembre 2006 à 11:00 :: Expériences :: permalien #29
Tags:
Il est des constructions que certains pensent légitimes, et qui pourtant ne le sont pas. On les retrouve de temps en temps dans le code source d’un projet, et il est évident que la lecture n’en est pas facilitée. L’une de des constructions est la terrible Boucle Infinie Qui En Fait N’Est Exécutée Qu’Une Fois.
Le coupable, dans sa grande splendeur, ressemble à ce pseudo-code C++ :
for (;;) {
// …
// quelques conditions peuvent permettre de sortir de la boucle
if (a_condition) break;
// …
// au final, on s’assure quand même que la boucle n’est exécutée
// qu’une seule fois.
break;
}
Le but de cette structure de code est généralement de permettre l’exécution du code jusqu’à un certain point, et en cas d’erreur il est alors possible de contrôler la sortie de la boucle pour ensuite exécuter (par exemple) le code qui libérera les ressources créées précédemment.
En d’autre terme, ce code permet, avec une écriture on ne peut moins idiomatique, de ne pas utiliser le mot-clef goto - puisque nous savons tous depuis Djikstra que goto est un mot clef dangereux. Il s’agit donc de reproduire le comportement dangereux de ce mot-clef sans l’utiliser – autrement dit, nous entrons là dans le royaume du non-sens.
Tout problème possédant une solution, comment peut-on éviter d’écrire ce code odieux ? Plusieurs techniques sont à notre disposition.
- dans un premier temps, si nous désirons contrôler les ressources créées, l’idiome RAII (pour Resource Acquisition Is Initialization) vient à notre secours. L’implémentation de cet idiome est d’une simplicité désarmante : la ressource est encapsulée dans un objet, la création de l’objet crée la ressource ou acquiert celle-ci, et la destruction de l’objet libère la ressource. En C++, si cette ressource est représentée par un bloc de mémoire, les classes
std::vectoretstd::auto_ptrpeuvent être utilisées. Dans le cas d’un fichier ou d’un flux, les classes dérivées destd::istreametstd::ostreamsont à considérer. Toute autre ressource peut être représentée par une classe dédiée. Lorsqu’on sort de la fonction (sur une erreur, par l’envoi d’une exception ou que sais-je), le destructeur sera systématiquement appelée et la ressource sera détruite. Le code client en est simplifié d’autant. L'idiome RAII peut être implémenté dans de nombreux autres langages (Java, C#, et ainsi si suite)
- Si nous devons gérer plusieurs cas d’erreurs, chaque cas devant initialiser une variable dans le but de retourner un code d’erreur, notre choix se portera sur la génération d’exceptions. Une exception peut être générée avec n’importe quel objet, ce qui peut nous permettre de créer l’objet souhaité (ou plus simplement de générer un code d’erreur, si il s’agit là de notre seul besoin).
D’autres techniques peuvent être mises en oeuvre pour éviter d’avoir à écrire un code douteux au mieux, dangereux au pire. Alors, s’il vous plait, éviter de faire l’erreur d’implémenter cette indécente boucle ! A bon entendeur...
Commentaires
Aucun commentaire pour le moment.
:: Fil rss des commentaires de ce billet ::
Ajouter un commentaire