Est-il toujours un besoin pour un “do {...} while ( )” de la boucle?
Bjarne Stroustrup (C++ créateur) a dit une fois, qu'il évite de "faire/tout en boucles, et préfère écrire le code dans une boucle "while" à la place. [Voir la citation ci-dessous.]
Depuis entendant cela, j'ai trouvé ceci pour être vrai. Quelles sont vos pensées? Est-il un exemple où un "do-while" est beaucoup plus propre et plus facile à comprendre que si vous avez utilisé un "tout" à la place?
En réponse à certaines des réponses: oui, je comprends la différence technique entre "do-while" et "tout". C'est une question plus profonde à propos de la lisibilité et de la structuration du code impliquant des boucles.
Laissez-moi vous poser une autre façon: supposons que l'on vous interdit de "faire/tout en" - est-il réaliste d'un exemple où cela vous donnerait pas le choix mais pour écrire impur code à l'aide de "tout"?
De "Le Langage De Programmation C++", 6.3.3:
Dans mon expérience, la déclaration est une source d'erreurs et de confusion. La raison en est que son corps est toujours exécutée une fois avant que la condition est évaluée. Cependant, pour le corps à fonctionner correctement, quelque chose de très semblable à la condition doit tenir même la première fois. Plus souvent que je l'aurais deviné, j'ai constaté que la condition de ne pas tenir comme prévu, soit lorsque le programme a d'abord été écrit et testé, ou plus tard, après le code précédent, il a été modifié. Je préfère aussi la condition "à l'avant où je peux le voir." Par conséquent, j'ai tendance à éviter de faire les relevés. -Bjarne
- La Révision du Code n'était pas encore autour de juin '09. Quel est votre point exactement?
- C'est vraiment une mauvaise recommandation...
- StackOverflow ou des Programmeurs.SE. La Revue de Code est uniquement pour code de travail et doit inclure le code. Cette question n'a pas de code de ce que-si-jamais. Ce qui le rend hors-sujet sur la Révision du Code.
- Qui fait sens. Je vais le faire.
- merci de voir un guide pour l'Examen du Code de Débordement de Pile utilisateurs.
- Je voudrais prendre le temps de lire cette méta post qui est assez vaste sur ce sujet. Il fournit un grand nombre de comprendre quelles sont les questions sur le sujet sur les Programmeurs.StackExchange. Espère que ça aide aussi!
Vous devez vous connecter pour publier un commentaire.
Oui je suis d'accord que faire lors de la boucle peut être réécrit pour une boucle while, cependant je suis en désaccord que toujours à l'aide d'une boucle while, c'est mieux. faire tout en reçois toujours exécuté au moins une fois et qui est très utile à la propriété (le meilleur exemple étant l'entrée de contrôle (clavier))
Cela peut bien sûr être réécrit pour une boucle while, mais ce qui est généralement considéré comme beaucoup plus élégant.
char
comme un marqueur spécial. Bien que cela n'affecte pas la logique ici, en général, cela signifie que vous n'êtes plus en mesure de traiter un flux de caractères arbitraires, car il peut contenir des caractères ayant la valeur -1.char
la mise en œuvre est définie, donc, en utilisant le nombre magique -1 n'est pas sage pour plus d'une raison, il pourrait y avoir un bug. Vous ne devriez pas tenter de stocker les nombres négatifs à l'intérieur de unsigned variables.do-while est une boucle avec une post-condition. Vous en avez besoin dans les cas où le corps de la boucle est exécutée au moins une fois. Ceci est nécessaire pour que le code qui a besoin d'une action avant de la condition de la boucle peut être raisonnablement évalué. Avec boucle while vous devez appeler le code d'initialisation de deux sites, avec le faire-alors que vous ne pouvez l'appeler à partir d'un seul site.
Un autre exemple est lorsque vous avez déjà un objet valide lors de la première itération est commencé, de sorte que vous ne souhaitez pas exécuter quoi que ce soit (condition de boucle d'évaluation inclus) avant la première itération commence. Un exemple en est avec FindFirstFile/FindNextFile fonctions Win32: vous appelez FindFirstFile qui renvoie soit à une erreur ou à une recherche de la poignée pour le premier fichier, puis vous appelez FindNextFile jusqu'à ce qu'il renvoie une erreur.
Pseudocode:
for(handle = FindFirstFile(params); handle != Error; handle = FindNextFile(params)) {}
.do { ... } while (0)
est une notion importante pour faire des macros à bien se comporter.Même si c'est sans importance dans le code réel (avec qui je ne suis pas forcément d'accord), il est important pour la fixation de certaines des lacunes du préprocesseur.
Edit: j'ai couru dans une situation où faire/tout était beaucoup plus propre aujourd'hui dans mon propre code. J'ai été faire une croix-plate-forme de l'abstraction de la paire LL/SC instructions. Ces le besoin d'être utilisée dans une boucle, comme ceci:
(Experts pourriez réaliser que oldvalue est pas utilisé dans un SC de mise en Œuvre, mais il est inclus afin que cette abstraction peut être émulée avec AR.)
LL et SC sont un excellent exemple d'une situation où do-while est nettement plus propre que l'équivalent, tandis que le formulaire:
Pour cette raison, je suis extrêmement déçu par le fait que Google Aller a opté pour retirer le faire-lors de la construction.
if
déclaration sans croisillons.C'est utile quand vous voulez "faire" quelque chose "jusqu'à" une condition est satisfaite.
Il peut être truqués dans une boucle while comme ceci:
(En supposant que vous savez la différence entre les deux)
Faire/Tout est bon pour l'amorçage/de pré-initialisation du code avant que votre condition est vérifiée et la boucle while est exécutée.
Dans nos conventions de codage
Donc, nous n'avons presque jamais un
do {} while(xx)
Parce que:
est remanié:
et
est remanié:
if (...) break;
), souvent même combiné avecwhile(true)
resp.for(;;)
. Donc, ce qui renddo ... while
, où vous avez au moins savoir où chercher de l'état, ou pire?if (bCondition) break;
une mauvaise conception et encouragé l'utilisation de bonne boucle conditions. Bien sûr, il y a un peu cas où il ne peut pas être évitée, mais la plupart du tempsbreak
etcontinue
sont des signes de paresseux de codage.Les communes suivantes idiome semble très simple pour moi:
La réécriture pour éviter
do
semble être:Que la première ligne est utilisé pour s'assurer que le test renvoie toujours true la première fois. En d'autres termes, le test est toujours superflue la première fois. Si ce superflu de test n'était pas là, on peut aussi omettre l'affectation initiale. Ce code donne l'impression qu'il se combat lui-même.
Dans un tel cas, la
do
construire, c'est une option très utile.Il est tout au sujet de lisibilité.
Un code plus lisible conduit à moins de maux de tête dans la maintenance du code, et une meilleure collaboration.
D'autres considérations telles que l'optimisation) sont, de loin, le moins important dans la plupart des cas.
Je vais essayer d'approfondir, depuis que j'ai eu un commentaire ici:
Si vous avez un extrait de code Un qui utilise
do { ... } while()
, et c'est plus lisible que seswhile() {...}
équivalent B, alors je vais voter pour Un. Si vous préférez B, puisque vous voyez la condition de la boucle "à l'avant", et vous pensez que c'est plus lisible (et donc facile à gérer, etc.) - alors allez-y, utilisez B.Mon point est: utilisez le code est plus lisible pour vos yeux (et vos collègues de travail). Le choix est subjectif, bien sûr.
C'est seulement un choix personnel à mon avis.
La plupart du temps, vous pouvez trouver un moyen de réécrire une boucle do ... while pour une boucle while, mais pas nécessairement toujours. Aussi il pourrait faire plus de sens logique à écrire une boucle do while, parfois, à s'adapter au contexte, vous êtes en.
Si vous regardez au-dessus, la réponse de TimW, il parle de lui-même. Le second, avec la Poignée, en particulier, est plus salissant à mon avis.
C'est plus propre alternative à-tandis que j'ai vu. C'est l'idiome recommandé pour Python qui n'ont pas un do-while.
Seul inconvénient est que vous ne pouvez pas avoir un
continue
dans le<setup code>
car il serait sauter à la condition d'arrêt, mais aucun de ces exemples qui démontrent les avantages de le faire-tout besoin d'un poursuivre, devant l'état.Ici, il est appliqué à certains des meilleurs exemples de l', tandis que les boucles ci-dessus.
L'exemple suivant est un cas où la structure est plus lisible qu'un faire-alors que la condition est conservée à proximité de la haut que
//get data
est généralement de courte encore la//process data
partie peut être longue.break
!Je ne jamais les utiliser, tout simplement parce que de l'suivantes:
Même si la boucle vérifie la post-condition, vous devez vérifier pour ce post condition au sein de votre boucle de sorte que vous n'avez pas le processus de la post-condition.
Prendre l'exemple de pseudo-code:
Semble simple en théorie, mais dans des situations du monde réel, il serait probablement une tournure ressemble à:
Le "si" check n'est tout simplement pas la peine de l'OMI. J'ai trouvé très peu de cas où il est plus laconique de faire un faire-alors qu'à la place d'une boucle while. YMMV.
while() {...}
est le choix approprié -while() {...}
est prévu pour exactement le cas où vous avez besoin d'exécuter du code zéro ou plusieurs fois en fonction d'une condition. Toutefois, cela ne signifie pas qu'il n'y a jamais de cas pourdo {...} while()
, des situations où vous savez que le code doit exécuter au moins une fois avant la vérification de l'état (voir la réponse sélectionnée à partir de @david-božjak).En réponse à une question/commentaire de l'inconnu (google) à la réponse de Dan Olson:
"do { ... } while (0) est une notion importante pour faire des macros à bien se comporter."
Voyez-vous ce qui se passe sans la
do { ... } while(0)
? Il sera toujours exécuté doAnother().Lire la Programme Structuré Théorème. Un do{} while() peut toujours être réécrit pour tout() do{}. La séquence, la sélection, et l'itération ne sont plus que jamais nécessaires.
Puisque tout ce qui est contenu dans le corps de la boucle peut toujours être encapsulé dans une routine, la saleté de l'avoir à l'utiliser tout en() do{} n'a jamais besoin d'obtenir de pire que de
for (bool first=true; first || cond; first=false) { ... }
. Ce ne serait pas dupliquer le code, mais d'introduire une variable supplémentaire.Une boucle while peut toujours être réécrit comme une boucle while.
Que d'utiliser uniquement en boucles, ou while, do-while, et pour des boucles (ou toute combinaison de ceux-ci) dépend de votre goût pour l'esthétique et les conventions de la le projet sur lequel vous travaillez.
Personnellement, je préfère tout-boucles car il simplifie le raisonnement sur les invariants de boucle à mon humble avis.
Si il y a des situations où vous avez besoin, tandis que les boucles: au Lieu de
vous pouvez toujours
donc, non, vous n'avez jamais besoin de l'utiliser, tandis que si vous ne pouvez pas pour une raison quelconque. (Bien entendu, cet exemple viole SEC, mais c'est seulement une preuve de concept. Dans mon expérience, il est généralement un moyen de transformer un do-while pour une boucle while et de ne pas violer SEC en aucun cas concret d'utilisation.)
"When in Rome, fais comme les Romains."
BTW: Le devis que vous cherchez est peut-être celui-ci ([1], le dernier alinéa de l'article 6.3.3):
(Note: C'est ma traduction de l'édition allemande. Si vous possédez l'édition en anglais, n'hésitez pas à modifier le devis pour correspondre à sa formule originale. Malheureusement, Addison-Wesley déteste Google.)
[1] B. Stroustrup: Le langage de programmation C++. La 3e Édition. Addison-Wessley, La Lecture, 1997.
Tout d'abord, je suis d'accord que
do-while
est moins lisible quewhile
.Mais je suis étonné de voir qu'après tant de réponses, personne n'a demandé pourquoi
do-while
même qu'il existe dans la langue. La raison en est l'efficacité.Permet de dire que nous avons un
do-while
boucle avecN
contrôles des conditions, lorsque le résultat de la condition dépend du corps de la boucle. Alors, si nous le remplacer par unwhile
boucle, nous obtenonsN+1
condition vérifie plutôt, où la vérification supplémentaire est inutile. C'est pas une grosse affaire si la condition de la boucle ne contient qu'un chèque d'une valeur entière, mais disons que nous avonsL'appel de fonction dans le premier tour de la boucle est redondant: nous savons déjà que
x
n'est pas encore rien. Alors pourquoi exécuter certaines inutile surcharge de code?J'utilise souvent, tandis que pour cet effet lors du codage en temps réel de systèmes embarqués, d'où le code à l'intérieur de l'état est relativement lente (vérification de la réponse de certains lente matériel périphérique).
while (x == null || check(x)) . . .
traite de cette questionenvisager quelque chose comme ceci:
Il se trouve que le '\0' est 0, mais j'espère que vous obtenez le point.
SumOfString("")
.Mon problème avec ne/tout est strictement à sa mise en œuvre C. Grâce à la réutilisation de la tout mot-clé, c'est souvent du des voyages des gens de haut parce qu'elle ressemble à une erreur.
Si tout avaient été réservés seulement pour tout boucles et ne/tout avait été changé en ne/jusqu'à ou répéter/jusqu'à, je ne pense pas que la boucle (qui est certainement à portée de main et la "bonne" manière de coder certaines boucles) serait la cause de beaucoup de problèmes.
J'ai déclamée avant à propos de ce en ce qui concerne le JavaScript, qui a aussi hérité de ce triste choix de C.
while
dedo-while
sur la même ligne que le}
. Et il y a toujours un point-virgule à la fin. Aucun programmeur en C avec au moins un peu légère de la compétence devient confus ou "déclenché" lors de la rencontre de la ligne:} while(something);
.Peut-être bien que cela remonte à quelques pas, mais dans le cas de
Il serait possible, bien que pas forcément lisible pour utiliser
Maintenant, si vous souhaitez utiliser un nombre autre que 0 pour quitter la boucle
Mais encore une fois, il y a une perte de lisibilité, pour ne pas mentionner qu'il est considéré comme une mauvaise pratique d'utiliser une instruction d'affectation à l'intérieur d'un conditionnel, je voulais juste faire remarquer qu'il y a de plus en plus compacts façons de le faire que d'attribuer un "réservés" de la valeur à indiquer à la boucle qu'elle est la première à travers.
J'aime David Božjak l'exemple. Pour jouer l'avocat du diable, cependant, je pense que vous pouvez toujours le facteur le code que vous voulez exécuter au moins une fois dans une fonction distincte, la réalisation peut-être le plus lisible solution. Par exemple:
pourrait devenir ce:
(pardon pour toute erreur de syntaxe, je ne suis pas un programmeur C)