82 votes

Une boucle "for" qui semble être pratiquement infinie.

Je suis en train de déboguer du code en ce moment, et je suis tombé sur cette ligne :

for (std::size_t j = M; j <= M; --j)

(Écrit par mon patron, qui est en vacances.)

Ça me semble vraiment bizarre.

Que fait-il ? Pour moi, ça ressemble à une boucle infinie.

68voto

Bathsheba Points 23209

std::size_t est garantie par la norme C++ comme étant une unsigned type. Et si vous décrémentez un unsigned à partir de 0, la norme garantit que le résultat de cette opération est la plus grande valeur pour ce type.

Cette valeur enveloppée est toujours supérieure ou égale à M 1 et la boucle se termine.

Alors j <= M lorsqu'il est appliqué à un unsigned est une façon pratique de dire "exécuter la boucle jusqu'à zéro puis s'arrêter".

Des alternatives telles que la course à pied j un plus grand que ce que vous voulez, et même en utilisant la opérateur de glissement for (std::size_t j = M + 1; j --> 0; ){ existent, qui sont sans doute plus claires, mais nécessitent davantage de saisie. Je pense que l'un des inconvénients (outre l'effet déroutant qu'il produit à la première inspection) est qu'il ne se porte pas bien vers les langages sans types non signés, comme Java.

Notez également que le schéma choisi par votre patron "emprunte" une valeur possible à l'option unsigned set : il se trouve dans ce cas que M réglé sur std::numeric_limits<std::size_t>::max() n'aura pas le comportement correct. En fait, dans ce cas, la boucle est infinie. . (C'est ce que vous observez ?) Vous devriez insérer un commentaire à cet effet dans le code, et peut-être même faire une assertion sur cette condition particulière.


1 Sous réserve de M ne pas être std::numeric_limits<std::size_t>::max() .

27voto

paxdiablo Points 341644

Ce que votre patron était probablement en essayant à faire était de compter à rebours à partir de M à zéro inclus, en effectuant une action sur chaque nombre.

Malheureusement, il y a un cas limite où cela va en effet vous donne une boucle infinie, celle où M est le maximum size_t valeur que vous pouvez avoir. Et, bien qu'il soit bien défini ce qu'une valeur non signée fera lorsque vous la décrémentez de zéro, je maintiens que le code lui-même est un exemple de pensée bâclée, d'autant plus qu'il existe une solution parfaitement viable sans les défauts de la tentative de votre patron.

Cette variante plus sûre (et plus lisible, à mon avis, tout en maintenant une limite de portée serrée), serait :

{
    std::size_t j = M;
    do {
        doSomethingWith(j);
    } while (j-- != 0);
}

À titre d'exemple, voyez le code suivant :

#include <iostream>
#include <cstdint>
#include <climits>
int main (void) {
    uint32_t quant = 0;
    unsigned short us = USHRT_MAX;
    std::cout << "Starting at " << us;
    do {
        quant++;
    } while (us-- != 0);
    std::cout << ", we would loop " << quant << " times.\n";
    return 0;
}

Cela fait essentiellement la même chose avec un unsigned short et vous pouvez voir les processus chaque valeur unique :

Starting at 65535, we would loop 65536 times.

Remplacer le do..while dans le code ci-dessus avec ce que votre patron a fait en gros résultera en une boucle infinie. Essayez et voyez :

for (unsigned int us2 = us; us2 <= us; --us2) {
    quant++;
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X