ça tue pas les exceptions![]()
je ne dit pas que cela tue, je dit simplement qu'il ne faut pas en abuser.
Et c'est justement le but de la programmation par exception (qui était à la mode il n'y a pas si longtemps).....
après j'ai peu être mal choisi mes mots, il y'a aussi des endroits ou tu n'as pas le choix (pour les exception).
Je crois quand même qu'il ne faut pas tout mélanger...
D'un coté il y a le goto, qui *peut exceptionnellement* présenter certains intérêts, mais dans des situations tout à fait particulières.
En toute honnêteté, je n'ai jamais du y avoir recours, et je ne m'en porte pas plus mal: si on ne reste pas bloqué sur le principe (qui est devenu totalement obsolète) du SESE déjà évoqué.
Si on prend cinq minutes de réflexion au lieu de se jeter directement sur son clavier et de se mettre à "vomir" du code, on arrive parfaitement à s'en passer, et c'est tout bénef pour la lisibilité du code.
A l'extrême opposé, on a le système d'exception. Mais on est donc tenté de s'intéresser à ce qu'est une exception.
Ta vision qui essaye de dire qu'une exception doit être... exceptionnelle est finalement fort restrictive: quand on regarde les différentes exceptions lancées par la STL, on remarque en effet que s'il y a deux points communs entre toutes les exceptions, c'est:
- effectivement des événements qui ne se produisent (par chance) que rarement ou dont on peut dire que "ils peuvent arriver"
- des problèmes dont la source et, par la même occasion, les opportunités d'y apporter éventuellement une solution, se trouve généralement (largement) en amont:
- Si new échoue, ce sera le plus souvent parce que... trop de mémoire est déjà allouée dynamiquement
- Si l'ouverture (enfin, si l'accès à un fichier réputé ouvert) d'un fichier échoue, c'est sans doute parce qu'il a été "verrouillé" par le système par ailleurs (souvent en dehors de l'application, d'ailleurs
), ou parce que l'on a commis une erreur lorsqu'il a été question d'évaluer le nom (et le chemin d'accès) du fichier.
- Si la fonction at de la classe vector échoue, c'est, typiquement, parce que l'on a mal évalué le nombre d'éléments
- Si un transtypage (static_cast ou dynamic_cast) devant fournir une référence écouhe, c'est, typiquement, parce que l'on a mal identifié le type réel de l'objet référencé.
Le but d'un bloc try... catch est en réalité double:
Il ne faut pas non plus oublier qu'une exception transporte avec elle une information de contexte des plus utiles: les différentes événements cités plus haut lancent tous une exception différente (même si elles ont toutes une base commune), ce qui permet, lorsqu'on la récupère (parfois bien haut par rapport à l'endroit où l'événement s'est produit), d'apporter la meilleure réponse possible au problème.
- Il nous donne la possibilité de remettre le système dans un état cohérent si un événement "qui n'aurait pas du se produire" s'est produit, par exemple, en annulant des modifications qui n'avaient de sens que parce que l'on espérait que l'événement incriminé ne se produise pas.
- Il nous donne l'occasion de remonter à la source du problème, afin d'éviter qu'il ne se reproduise par la suite (s'il est possible d'y trouver une solution, du moins)
Dés lors, s'il est, effectivement, aberrant de vouloir placer du try... catch partout où une exception risque d'être lancée (un simple vector.add(value) peut en lancer une, vu que add risque d'appeler new, qui peut lancer une exception), il est tout aussi aberrant de vouloir comparer try... catch à un simple goto
Mais cela nous écarte du problème du PO... Et il existe déjà des débats relatifs aux avantages du goto et, je crois, des exceptions.
Je proposerais donc de recentrer le débat sur sa question existentielle qui concerne le continue.
Je l'ai déjà dit, je n'ai jamais eu à me servir d'un break en dehors d'un switch, case et je n'ai jamais eu besoin de me servir de continue.
Il serait bien sur présomptueux de ma part de dire que c'est peut être parce que je suis un bon programmeur, mais je constate que les circonstances m'ont toujours permis de m'en passer
Et je ne peux m'empêcher de rappeler encore une fois qu'aucune technique de programmation ne peut être considérée comme la solution ultime à tous les problèmes, et que son utilité doit impérativement être évaluée en fonction des circonstances auxquelles nous sommes confrontés.
L'instruction continue ne fait pas exception: S'il est vrai que, très souvent, son besoin est de nature à au minimum tirer une sonnette d'alarme qui devrait t'inciter à réfléchir sur l'opportunité d'un refactoring et / ou de la factorisation de ton code, il y a des cas où il devient impossible de s'en passer sans provoquer une complexification nuisible de la logique ou du code.
Dans ce genre de cas, son utilisation est, non seulement justifiée, mais aussi sans doute très largement préférable à toute autre solution![]()
A méditer: La solution la plus simple est toujours la moins compliquée
Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
Compiler Gcc sous windows avec MinGW
Coder efficacement en C++ : dans les bacs le 17 février 2014
mon tout nouveau blog
Personellement, je me reposer la question initiale a chaque fois que je tombe sur un cas où je doute.
Ce qui fait que je fais du "cas par cas". Donc parfois je l'utilise.
Il m'arrive souvent de faire des fonctions de recherche sous cette forme (pseudocode) :
C'est pas des continue mais c'est le même genre de questionnement non?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8 fonction findMachin( string name ) return Machin for each machin in machins if machin.name == name return machin return null end
Pour les continue, il m'arrive d'en faire quand j'ai besoin de parcourir les éléments d'un conteneur pour faire plusieurs tests de "validation" avant d'effectuer une action dessu :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 fonction validation() for each machin in machins if machin.name == "" || !isConditionA( machin ) // etc... continue //toutes les conditions sont passées action( machin ) end
Mais souvent quand le code prends plusieurs lignes ou aparait comme utilisable ailleurs, je factorise :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 fonction validation() for each machin in machins if checkAllConditions( machin ) action( machin ) end function checkAllConditions( Machin machin ) return bool //...
Du coup, beaucoup de continue pourraient être remplacés par une fonction avec un retour booleen.
Ca m'arrive quand même d'en utiliser mais seulement quand je n'ai pas pris le temps de refactorer une fonction ou bien quand le code reste suffisamment simple pour rester lisible même apres l'ajout du continue.
Salut,
Pour moi, c'est pas tout à fait la même chose en terme de lecture de code. Un return, tu vois bien que tu sorts directement de la fonction.
Les break/continue que j'ai vu c'était plutôt comme screetch les décrit :
Et comme le dit Luc, le problème c'est /* plein de trucs */.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 { if(blablabla) break; /* plein de trucs */ if(dobidouwa) break; /* plein de trucs */ }
Cependant, j'ai l'impression que si on n'avait pas /* plein de trucs */, on n'aurait pas besoin de break/continue.
Ressources proposées par 3DArchi - Les fonctions virtuelles en C++ - Cours et tutoriels C++ - FAQ C++ - Forum C++.
Je me sers de continue de temps en temps (12 occurrences sur 40 000 lignes de code, c'est pas énorme non plus).
La plupart du temps, c'est pour changer :
... en :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 for (...) { // Faire deux trois choses (ou rien du tout) if (caVaMal) { // Traiter le cas qui ne fonctionne pas } else { // Poursuivre le traitement } }
Je trouve que ça améliore la lisibilité (on vois tout de suite avec continue que le traitement est abandonné pour cette itération), et ça évite d'avoir trop d'indentation...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 for (...) { // Faire deux trois choses (ou rien du tout) if (caVaMal) { // Traiter le cas qui ne fonctionne pas continue; } // Poursuivre le traitement }
D'autre fois c'est simplement une question d'algorithme. Par exemple en détection de collision entre deux objets 3D, on essaye de faire un minimum de traitement pour chaque triangle du maillage. On passe donc à l'itération suivante dès qu'on est sûr que le triangle qu'on étudie n'entrera pas en collision, d'où l'emploi de continue.
Honnêtement, si vous savez lire un return ailleurs qu'en fin de fonction, alors je ne vois pas de problème à mettre des break et des continue partout(bon, avec modération comme toutes les bonnes choses). C'est la même gymnastique intellectuelle.
Partager