web-dev-qa-db-fra.com

Est-il bon de définir une variable à l'intérieur d'une boucle?

Mon instructeur m'a dit une fois que je ne devrais pas définir une variable à l'intérieur d'une boucle, mais honnêtement, je ne comprends toujours pas pourquoi.

Quels en sont les inconvénients?

Quelqu'un pourrait-il m'expliquer cela?

16
user3260672

Ce n'est pas un problème pour définir une variable dans une boucle. En fait, c'est une bonne pratique, car les identifiants doivent être limités à la plus petite portée possible.

Ce qui est mauvais, c'est de assigner une variable dans une boucle si vous pouvez aussi bien l'attribuer une fois avant la boucle s'exécute. Selon la complexité du côté droit de l'affectation, cela pourrait devenir assez coûteux et même dominer le temps d'exécution de la boucle. Si vous écrivez une boucle qui utilise la même valeur calculée dans toutes les itérations, vous devez certainement la calculer au-dessus de la boucle - ce qui est plus important que de minimiser sa portée .

Pour clarifier: tant que compute() renvoie toujours la même valeur, cette

int value = compute();
while (something) {
    doSomething(value);
}

est plus intelligent que cela:

while (something) {
    int value = compute();
    doSomething(value);
}
43
Kilian Foth

Les types complexes ont des constructeurs et des destructeurs non triviaux.

Ceux-ci seront appelés au début et à la fin du corps de la boucle (car il est initialisé et hors de portée). Si l'initialisation est coûteuse, car elle doit allouer de la mémoire, cela doit être évité.

Cependant pour les types triviaux ce n'est pas un problème. L'allocation et la désallocation elles-mêmes ajoutent et soustraient simplement une valeur du pointeur de pile. (qui sera optimisé)

16
ratchet freak

Eh bien, son conseil est légèrement trop simple (c'est un euphémisme).
La suite va de ne bonne idée à peu importe et mauvaise idée à impossible =.

  1. Vous devez le suivre chaque fois que la réutilisation est moins chère que de détruire l'ancien et d'en créer un nouveau.

    #include <iostream>
    #include <string>
    
    int main() {
        std::string s; // Don't needlessly free the buffer
        while ((std::cin >> s))
            std::cout << s;
    }
    
  2. Vous devez l'éviter par style lorsque cela n'a pas d'importance pour les performances.

    #include <stdio.h>
    #include <stdlib.h>
    int f(int, int);
    
    int main() {
        for (int i = 0; i < 100; ++i) {
            int x = Rand(); // Declared here so you don't need to hunt it down.
            printf("%d => %d\n", x, f(x-1, x+i));
        }
    }
    
  3. Vous vraiment devriez l'éviter quand il a de moins bonnes performances ou une mauvaise sémantique.

    #include <iostream>
    #include <string>
    std::string generate(int);
    
    int main() {
        for(int i = 0; i < 100; ++i) {
            std::string s = generate(i); // Using copy-ellision here
            std::cout << s;
        }
    }
    
  4. Vous ne pouvez pas le suivre lorsque le type utilisé ne permet ni l'échange, ni l'assignation de déplacement ni l'assignation de copie.

    #include <iostream>
    #include <puzzle>
    
    int main() {
        for (int i = 0; i < 100; ++i) {
            Puzzle x(i); // Puzzle is an immutable class. For whatever reasons.
            std::cout << x;
        }
    }
    
6
Deduplicator