Supposons que vous ayez la for
boucle suivante *:
for (int i = 0; i < 10; ++i) {
// ...
}
qui pourrait aussi s'écrire:
for (int i = 0; i != 10; ++i) {
// ...
}
Les résultats finaux sont les mêmes, donc y a-t-il des arguments réels pour utiliser l'un sur l'autre? Personnellement, j'utilise l'ancien au cas où, i
pour une raison quelconque, se détraquerait et sauterait la valeur 10.
* Excusez l'utilisation des nombres magiques, mais ce n'est qu'un exemple.
int i = 10; while(i --> 0) { /* stuff */ }
while ((i--) > 0)
Réponses:
La raison de choisir l'un ou l'autre est en raison de l' intention et en conséquence, cela augmente la lisibilité .
Intention: la boucle doit s'exécuter aussi longtemps qu'elle
i
est inférieure à 10, pas aussi longtemps qu'ellei
n'est pas égale à 10. Même si cette dernière peut être la même dans ce cas particulier, ce n'est pas ce que vous voulez dire, donc elle ne devrait pas être écrit comme ça.Lisibilité: en écrivant ce que vous voulez dire, c'est aussi plus facile à comprendre. Par exemple, si vous utilisez
i != 10
, quelqu'un qui lit le code peut se demander si à l'intérieur de la boucle il y a un moyen quii
pourrait devenir plus grand que 10 et que la boucle devrait continuer (btw: c'est un mauvais style de jouer avec l'itérateur ailleurs que dans la tête de lafor
déclaration, mais cela ne signifie pas que les gens ne le font pas et, par conséquent, les responsables s'y attendent).la source
i
est «inférieure à 10», elle doit s'exécuter tant que la limite supérieure (dans ce cas) n'est pas atteinte. Lorsque vous utilisez la logique d'intervalle / intervalle C ++, il est beaucoup plus logique d'exprimer cela via!=
que<
.<
cela exprime cela précisément.for
boucle. Utiliser<
ici serait idiot. Deckard semble également le reconnaître. Je suis tout à fait d'accord avec son commentaire en réponse au mien.!=
Le
<
modèle est généralement utilisable même si l'incrément n'est pas exactement 1.Cela permet une seule façon commune de faire des boucles, quelle que soit la façon dont cela est réellement fait.
la source
i
de modifier l'intérieur de la boucle en toute sécurité si besoin est.<
, tels que les itérateurs sur une séquence, et!=
serait donc une seule façon courante de faire des boucles en C ++.<
modèle car il nécessite une frappe au lieu de deux avec le>
modèle et quatre avec!=
. C'est vraiment une question d'efficacité de type OCD.En C ++, la recommandation de Scott Myers dans C ++ plus efficace (élément 6) est toujours d'utiliser la seconde, sauf si vous avez une raison de ne pas le faire, car cela signifie que vous avez la même syntaxe pour les index d'itérateur et d'entier afin que vous puissiez échanger de manière transparente entre
int
et itérateur. sans aucun changement de syntaxe.Dans d'autres langues, cela ne s'applique pas, donc je suppose que
<
c'est probablement préférable en raison de l'argument de Thorbjørn Ravn Andersen.Soit dit en passant, l'autre jour , je discutais avec un autre développeur et il a dit la raison de préférer
<
plus!=
est parce quei
pourrait incrémenter accidentellement par plus d'un, et qui pourrait causer la condition de rupture ne soit pas présente; c'est IMO une charge de non-sens.la source
<
être une programmation plus défensive!=
<
est plus défensif et mes collègues détestent si j'écris!=
donc je ne le fais pas. Cependant, il y a un cas pour!=
en C ++ et c'est ce que j'ai présenté.i++
consiste à changer une boucle while en une boucle for. Pas sûr cependant que d'avoir la moitié du nombre d'itérations soit mieux qu'une boucle (presque) infinie; ce dernier rendrait probablement le bug plus évident.L'utilisation de (i <10) est à mon avis une pratique plus sûre. Il attrape le nombre maximum de cas de sortie potentiels - tout ce qui est supérieur ou égal à 10. Comparez cela avec l'autre cas (i! = 10); il n'attrape qu'un seul cas de sortie possible - lorsque i est exactement 10.
Un sous-produit de cela est qu'il améliore la lisibilité. De plus, si l'incrément est différent de 1, cela peut aider à minimiser la probabilité d'un problème si nous commettons une erreur lors de l'écriture du cas de fermeture.
Considérer:
Bien que les deux cas soient probablement défectueux / incorrects, le second est probablement plus faux car il ne s'arrêtera pas. Le premier cas se fermera, et il y a plus de chances qu'il s'arrête au bon endroit, même si 14 est probablement le mauvais numéro (15 serait probablement mieux).
la source
Voici une autre réponse que personne ne semble avoir encore trouvée.
for
les boucles doivent être utilisées lorsque vous devez parcourir une séquence . L'utilisation!=
est la méthode la plus concise pour énoncer la condition de fin de la boucle. Cependant, l'utilisation d'un opérateur moins restrictif est un idiome de programmation défensive très courant. Pour les entiers, cela n'a pas d'importance - c'est juste un choix personnel sans exemple plus spécifique. Boucler les collections avec les itérateurs que vous souhaitez utiliser!=
pour les raisons que d'autres ont indiquées. Si vous envisagez des séquences defloat
oudouble
, alors vous voulez éviter!=
à tout prix.Ce que je voulais souligner, c'est qu'il
for
est utilisé lorsque vous avez besoin d'itérer sur une séquence. La séquence générée a un point de départ, un intervalle et une condition de fin. Ceux-ci sont spécifiés de manière concise dans lafor
déclaration. Si vous vous trouvez soit (1) n'incluant pas la partie étape dufor
ou (2) spécifiant quelque chose commetrue
la condition de garde, alors vous ne devriez pas utiliser defor
boucle!La
while
boucle est utilisée pour poursuivre le traitement lorsqu'une condition spécifique est remplie. Si vous ne traitez pas une séquence, vous voudrez probablement unewhile
boucle à la place. Les arguments de la condition de garde sont similaires ici, mais la décision entre awhile
et unefor
boucle doit être très consciente. Lawhile
boucle est sous-estimée dans les cercles C ++ IMO.Si vous
for
traitez une collection d'éléments (une utilisation très courante en boucle), vous devriez vraiment utiliser une méthode plus spécialisée. Malheureusement,std::for_each
c'est assez douloureux en C ++ pour un certain nombre de raisons. Dans de nombreux cas, séparer le corps d'unefor
boucle dans une fonction autonome (bien que quelque peu douloureuse) donne une solution beaucoup plus propre. Lorsque l'on travaille avec des collections, pensezstd::for_each
,std::transform
oustd::accumulate
. La mise en œuvre de nombreux algorithmes devient concise et limpide lorsqu'elle est exprimée de cette manière. Sans oublier que l'isolement du corps de la boucle dans une fonction / méthode séparée vous oblige à vous concentrer sur l'algorithme, ses exigences d'entrée et ses résultats.Si vous utilisez Java, Python, Ruby ou même C ++ 0x , vous devez alors utiliser une boucle foreach de collecte appropriée . Au fur et à mesure que les compilateurs C ++ implémentent cette fonctionnalité, un certain nombre de
for
boucles disparaîtront, tout comme ces types de discussions.la source
while
,for
etforeach
(ou l'équivalent linguistique)while
boucle est utilisée pour continuer le traitement jusqu'à ce qu'une condition spécifique ne soit pas remplie<
) ou l'opérateur étant indulgent dans les valeurs qu'il échoue (!=
).Utiliser "moins de" est (généralement) sémantiquement correct, vous voulez vraiment dire que compter jusqu'à
i
n'est plus inférieur à 10, donc "moins de" exprime clairement vos intentions. L'utilisation de "non égal" fonctionne évidemment dans des cas d'appels virtuels, mais donne une signification légèrement différente. Dans certains cas, c'est peut-être ce dont vous avez besoin, mais d'après mon expérience, cela n'a jamais été le cas. Si vous aviez vraiment un cas où ili
pourrait y avoir plus ou moins de 10 mais que vous voulez continuer à boucler jusqu'à ce qu'il soit égal à 10, alors ce code aurait vraiment besoin de commenter très clairement, et pourrait probablement être mieux écrit avec une autre construction, comme en tant quewhile
boucle peut-être.la source
L'une des raisons pour lesquelles je préférerais un
less than
sur unnot equals
est d'agir comme gardien. Dans certaines circonstances limitées (mauvaise programmation ou désinfection), celanot equals
pourrait être ignoré alors qu'illess than
serait toujours en vigueur.Voici un exemple où l'absence d'un contrôle de désinfection a conduit à des résultats étranges: http://www.michaeleisen.org/blog/?p=358
la source
Voici une raison pour laquelle vous préféreriez peut-être utiliser
<
plutôt que!=
. Si vous utilisez un langage qui a une portée globale de variable, que se passe-t-il si un autre code est modifiéi
? Si vous utilisez<
plutôt que!=
, le pire qui se passe est que l'itération se termine plus rapidement: peut-être d'autres incréments de codei
par accident, et vous sautez quelques itérations dans la boucle for. Mais que se passe-t-il si vous bouclez de 0 à 10, que la boucle arrive à 9 et que certains incréments de thread sont mal écritsi
pour une raison étrange. Ensuite, votre boucle termine cette itération et incrémente dei
sorte que la valeur soit maintenant 11. Comme la boucle a ignoré la condition de sortie (i
jamais égale à 10), elle va maintenant boucler infiniment.Cela ne doit pas nécessairement être une logique de type threading-and-global-variables particulièrement bizarre qui provoque cela. Il se peut que vous écriviez une boucle qui doit revenir en arrière. Si vous mutez
i
à l'intérieur de la boucle et que vous bousillez votre logique, la faire en sorte qu'elle ait une limite supérieure plutôt qu'un a!=
est moins susceptible de vous laisser dans une boucle infinie.la source
Dans le monde embarqué, en particulier dans les environnements bruyants, vous ne pouvez pas compter sur la RAM se comportant nécessairement comme il se doit. Dans une conditionnelle (pour, tandis que, si) où vous comparez en utilisant '==' ou '! =' Vous courez toujours le risque que vos variables sautent cette valeur cruciale qui termine la boucle - cela peut avoir des conséquences désastreuses - Mars Lander conséquences de niveau. L'utilisation de «<» ou «>» dans la condition fournit un niveau de sécurité supplémentaire pour attraper les «inconnues inconnues».
Dans l'exemple d'origine, si elles
i
étaient inexplicablement catapultées à une valeur bien supérieure à 10, la comparaison '<' intercepterait l'erreur immédiatement et quitterait la boucle, mais '! =' Continuerait à compter jusqu'à ce qu'elle soiti
enroulée autour de 0 et retour au 10.la source
for (i=4; i<length; i++) csum+=dat[i];
où les paquets légitimes auraient toujourslength
au moins quatre, mais l'un pourrait recevoir des paquets corrompus. Si différents types de paquets ont des exigences de longueur différentes, on peut souhaiter valider la longueur dans le cadre du traitement qui est différent pour chaque type de paquet, mais valider d'abord la somme de contrôle dans le cadre de la logique commune. Si un paquet de longueur insuffisante est reçu, peu importe que le calcul de la somme de contrôle signale "bon" ou "mauvais", mais il ne devrait pas planter.