Une boucle ‘for’ qui semble être pratiquement infinie

Je débogue 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.)

Cela me semble vraiment étrange.

Qu’est ce que ça fait? Pour moi, cela ressemble à une boucle infinie.

std::size_t est garanti par le standard C ++ comme étant un type unsigned . Et si vous décrémentez un type unsigned de 0, le standard 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 pour que la boucle se termine.

Donc, j <= M lorsqu'il est appliqué à un type unsigned est une manière pratique de dire "exécuter la boucle à zéro puis arrêter".

Des alternatives telles que l'exécution de j un plus grand que vous voulez, et même l'utilisation de l' opérateur de diapositive for (std::size_t j = M + 1; j --> 0; ){ sont plus claires bien que nécessitant plus de frappe. Je pense toutefois qu'un inconvénient (à part l'effet déconcertant qu'il produit lors de la première inspection) est qu'il ne porte pas correctement sur les langages sans types non signés, tels que Java.

Notez également que le schéma que votre patron a choisi "emprunte" une valeur possible à l’ensemble unsigned : il se trouve que M défini sur std::numeric_limits::max() n’aura pas le même comportement correct. En fait, dans ce cas, la boucle est infinie . (Est-ce ce que vous observez?) Vous devriez insérer un commentaire à cet effet dans le code, et peut-être même l'affirmer.


1 Sous réserve que M ne soit pas std::numeric_limits::max() .

Ce que votre patron essayait probablement de faire était de décompter de M à zéro, en effectuant des actions sur chaque numéro.

Malheureusement, il y a une casse où cela vous donnera une boucle infinie, celle où M est la valeur maximale de size_t que vous pouvez avoir. Et, bien qu’il soit bien défini ce que fera une valeur non signée lorsque vous la décrémentez de zéro, je maintiens que le code lui-même est un exemple de reflection négligée, d’autant plus qu’il existe une solution parfaitement viable sans les défauts de votre tentative de patron.

Cette variante plus sûre (et plus lisible, à mon avis, tout en maintenant une limite de scope restreinte) serait:

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

A titre d’exemple, voir le code suivant:

 #include  #include  #include  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 qu'il traite chaque valeur:

 Starting at 65535, we would loop 65536 times. 

Remplacer la boucle do..while dans le code ci-dessus par ce que votre patron a fait fondamentalement entraînera une boucle infinie. Essayez-le et voyez:

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