Question

Je viens de trouver ... ENCORE ... un bogue de gaspillage en temps réel, comme suit

for (int i = 0; i < length; i++)
{ //...Lots of code 
    for (int j = 0; i < length; j++)
    {
        //...Lots of code 
    }
}

Avez-vous remarqué tout droit l’intérieur qui devrait être j? Moi non plus, alors je vais maintenant utiliser:

for (int i = 0; i < length; i++)
{
    for (int i1 = 0; i1 < length; i1++)
    {
    }
}

Quels sont vos conseils pour les boucles while et for internes et externes?

Edit: Merci pour vos précieuses réponses. Voici un bref résumé des conseils proposés:

  • utilise des noms de variables significatifs pour les variables d'index (j'utilise plutôt SomeObjCollectionLength)
  • place le contenu de la boucle interne dans une méthode distincte et appelle cette méthode à partir de la boucle externe
  • La quantité non gérable de lignes de code entre la boucle externe et la boucle interne est un signal fort pour l'odeur de code
  • évitez de copier-coller et de vous dépêcher, écrivez les variables d'index avec soin

Vous pouvez consulter le récapitulatif à l'aide de LBushkin pour le suivants

  • utilisez foreach et les itérateurs autant que possible
  • initialisez les variables juste avant d'entrer dans les boucles
  • Faire en sorte que chaque boucle n'exécute qu'une seule fonction. Évitez de mélanger les responsabilités dans une seule boucle
  • Lorsque cela est possible, raccourcissez vos boucles pour tout afficher en même temps
Était-ce utile?

La solution

N'utilisez pas i & amp; j (ou toute autre variable simple lettre) en tant que noms d'index. Utilisez des noms propres et vous ne rencontrerez pas ce type de problèmes.

Autres conseils

L’une des solutions les plus simples et les plus propres consiste à placer le contenu de la boucle interne dans une méthode afin qu’elle devienne:

for (int i = 0; i < length; i++)
{
    DoSomething();
}

private void DoSomething(int outerValue)
{
    for (int i = 0; i < length; i++)
    {
        // Do something else
    }

}

Pour moi, l'odeur du code est "beaucoup de code".

Si la quantité de code dans les boucles est particulièrement importante, la distance entre les boucles interne et externe signifie qu’elles ne sont pas aussi susceptibles d’être comparées les unes aux autres pour être correctes.

Certes, examiner le début de la boucle interne de manière isolée devrait attirer l’attention sur le problème, mais le fait de disposer de la structure principale dans une section de code aussi petite que possible rend votre cerveau moins digeste.

Il peut être possible d'extraire les sections 'beaucoup de code' dans des fonctions / méthodes distinctes, afin de réduire la taille de la structure principale - mais cela peut ne pas toujours être pratique.

De plus, je dirais que "i1" n'est pas un choix particulièrement judicieux de nom de variable, car cela a tendance à encourager "i2", "i3", etc., ce qui ne conduit pas vraiment à un code compréhensible. Peut-être que remplacer toutes les variables de la boucle par quelque chose de plus significatif aiderait à la clarté du code et réduirait les risques d'erreur d'origine.

Mon meilleur conseil (sans ordre particulier) pour écrire un meilleur code de boucle (cela provient en grande partie de l'excellent livre Code complet ):

  1. Évitez les points de sortie multiples pour les boucles.
  2. Utilisez continue / break avec parcimonie.
  3. Refactorisez les boucles imbriquées dans des routines distinctes, lorsque cela est possible.
  4. Utilisez des noms de variable significatifs pour rendre les boucles imbriquées lisibles.
  5. Utilisez des boucles foreach () autant que possible plutôt que pour des boucles (i = ...).
  6. Entrez la boucle à partir d'un seul endroit. Ne sautez pas dans une boucle avec les goto. Jamais.
  7. Placez le code d'initialisation immédiatement avant la boucle.
  8. Conservez les instructions d'initialisation de boucle avec la boucle à laquelle elles sont associées.
  9. Évitez de réutiliser des variables entre des boucles non imbriquées. 10. Limitez la portée des variables d’index de boucle à la boucle elle-même.
  10. Utilisez while (true) pour des boucles infinies, plutôt que pour (;;)
  11. Dans les langues qui fournissent des constructions de blocs (par exemple, '{' et '}'), utilisez-les plutôt que d'indenter pour inclure les instructions d'une boucle. Oui, même pour les boucles à ligne unique.
  12. Évitez les boucles vides.
  13. Évitez de placer des tâches ménagères au milieu d'une boucle, placez-les au début et / ou à la fin.
  14. Faire en sorte que chaque boucle n'exécute qu'une seule fonction. Évitez de mélanger les responsabilités dans une seule boucle.
  15. Rendre les conditions de terminaison de boucle évidentes.
  16. Ne claquez pas avec la variable d'index de boucle d'une boucle for () pour la terminer.
  17. Évitez le code qui dépend de la valeur finale de l'indexeur de la boucle.
  18. Pensez à utiliser des compteurs de sécurité dans les boucles complexes. Vous pouvez les vérifier pour vous assurer que la boucle ne s'exécute pas trop ou trop peu de fois.
  19. Utilisez des instructions de séparation, lorsque cela est possible, pour terminer les boucles While.
  20. Lorsque cela est possible, raccourcissez vos boucles pour tout voir en même temps.

C’est une erreur de copier / coller, évitez de copier / coller.

Quant à votre solution, ce n’est pas beaucoup mieux. L'erreur peut toujours glisser entre des tonnes de code. J'ai tendance à utiliser des noms significatifs même pour les variables temporaires de boucle.

exploitez votre environnement de développement, sur le VS, essayez ceci: http://msdn.microsoft.com/en-us/library/z4c5cc9b (VS.80) .aspx

exemple: saisissez pour , puis appuyez successivement sur Onglet

.

Je suis venu ici pour faire preuve d'intelligence et dire "je viens de l'écrire correctement dès la première fois". Mais ensuite, j’ai vu votre exemple et, eh bien, je l’ai fait trop souvent moi-même.

Lorsque vous avez besoin de boucles imbriquées de cette manière, ma seule solution consiste à rester vigilant et à réfléchir lorsque vous écrivez le code.

Dans la mesure du possible, utiliser des itérateurs et pour chaque boucle est agréable.

De plus, je ne vois pas comment votre solution proposée serait meilleure. Et ça n’a pas l’air aussi bien.

Tout d’abord, réduisez la taille du corps de la boucle, c’est-à-dire déplacez le contenu dans des fonctions distinctes. Il est généralement déconseillé d’utiliser des fonctions plus longues que ce qui peut être intégré à l’écran. Les boucles devraient donc être encore plus petites.

Deuxièmement, utilisez des noms de variable significatifs dans des cas comme celui-ci. Je n'utiliserais que i et j dans des boucles simples avec quelques lignes de code. Par exemple, si vous passez par un tableau à deux dimensions, " col " et " rangée " Cela aurait plus de sens, rendrait le code plus facile à lire ("qui était lequel?") et plus facile à repérer de telles erreurs.

Vous devez simplement prendre des précautions supplémentaires, il n’ya pas de solution miracle à ce problème. Même avec "mieux nommer" vous proposez de perdre de temps en temps la question de savoir s'il s'agit du Nième ou du (N + M) ème niveau de la boucle imbriquée et faites une erreur.

Si une boucle imbriquée est nécessaire, écrivez-la attentivement. Si cela peut être évité en extrayant le corps de la boucle externe dans une fonction qui constituerait une bonne protection contre les abus.

J'utilise 'ii' et 'jj' pour les compteurs de boucles transitoires si j'en ai vraiment besoin - ils sont plus faciles à rechercher que 'i' et 'j' et également plus faciles à repérer dans les exemples ci-dessus. Pour aller mieux, vous pouvez utiliser un vrai nom de variable. Si vous passez en boucle sur une chaîne, vous pouvez l'appeler characterIndex ou quelque chose du genre. C’est plus courant, mais cela se documente et fait gagner du temps sur le débogage d’obscurs problèmes plus tard.

Mieux encore, évitez les compteurs numériques et utilisez des itérateurs nommés au-dessus d’une collection. À mon avis, ils clarifient l’intention.

Enfin, si possible, il est bon de supprimer complètement la boucle: Boost :: Foreach est un moyen de le faire en C ++, bien que je préfère généralement utiliser des langages tels que Python qui autorisent de manière native une itération directe sur le contenu d'un conteneur sans qu'il soit nécessaire d'incrémenter une valeur d'index. itérateur.

Essayez d’utiliser davantage de constructions de boucle déclaratives. Par exemple, si vous n'avez pas vraiment besoin d'index (ces i s et j s) et que votre environnement de programmation le permet, vous pouvez utiliser un foreach pour parcourir la collection.

Comme dans tout cela, le Code complet de Steve McConnell contient d'excellents conseils. Ce serait bien de perdre votre temps à lire ce qu'il a à dire sur la construction d'un bon code en boucle. Je n'ai pas ma copie du livre à portée de main ici, mais tout le livre vaut votre temps.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top