Pour boucle à l'intérieur de ses propres accolades


117

Je suis tombé sur cette disposition pour la boucle:

#include <iostream>
int main()
{
    {
        for (int i = 0; i != 10; ++i)
        {
            std::cout << "delete i->second;" << std::endl;
        }
    }

    {
        for (size_t i = 0; i < 20; ++i)
        {
            std::cout << "delete m_indices[i];" << std::endl;
        }
    }
    return 0;
}

Je me demandais à quoi sert cette couche supplémentaire d'accolades? Cela apparaît plusieurs fois dans notre base de code.


47
Ils sont complètement superflus dans l'extrait de code que vous avez posté
EdChum

25
quels compilateurs ont été utilisés avec ce code? Plus précisément, VS 6 a-t-il été utilisé?
UKMonkey

5
@EdNorman maintenant avec votre modification, c'est beaucoup plus clair. Il semble que la bonne réponse soit celle fournie par UKMonkey. Avec le compilateur C ++ moderne, vous pouvez simplement supprimer les accolades.
Jabberwocky

8
Alternativement, il pourrait être généré du code (soupira quelqu'un qui vient juste de se
saisir de

4
Une raison possible est si le code avait une fois (ou est censé avoir à l'avenir) des directives parallèles OpenMP.
jamesqf

Réponses:


286

Il était une fois, il y a de nombreuses lunes, VS6 existait et était populaire. Il n'a cependant pas réussi à se conformer à un certain nombre de normes C ++; ce qui était raisonnable à l'époque car il a été publié juste avant (la même année) la norme a été officiellement publiée; il a toutefois adhéré au projet de norme pour autant que je sache.

L'une des normes qui a changé entre le projet et la norme officielle était la durée de vie des variables de boucle for créées dans la première section; conduisant à l'échec de la compilation du code suivant

{
    for (int i=0; i<1; ++i){}
    for (int i=0; i<2; ++i){}
}

car i été redéfini par la deuxième boucle for.

Alors que d'autres compilateurs ont également souffert de ce bogue; Je souligne le VS6 car il est resté la seule version de Visual Studio pendant un certain nombre d'années après la sortie de la norme, mais n'a jamais publié de mise à jour pour ce problème particulier; ce qui signifie qu'il a eu un impact plus significatif.

Une solution à cela est de forcer l'ensemble de la boucle for dans sa propre portée comme vous l'avez montré.


49
Inutile de trouver VS6 pour voir que @bolov, réglez "Force Conformance in For Loop Scope" sur "No" dans VS2015, et profitez-en ;-)
alain

5
@alain "l'option 'Zc: forScope-' est obsolète et sera supprimée dans une prochaine version" et se compile sans problème ... Je suis triste
bolov

7
GCC avant la version 2.7 présentait également ce comportement. Voir docs.freebsd.org/info/g++FAQ/g++FAQ.info.for_scope.html
Jeremy

5
@Damon ce n'était pas quand VS6 est sorti pour la première fois; cependant, lorsque les normes ont changé, une mise à jour qui s'y conforme n'a jamais été publiée. VS6 est resté populaire pendant quelques années après la modification des normes.
UKMonkey

7
Attribuer cela à un péché d'un ancien compilateur Microsoft est faux. Ce comportement était en fait une fonctionnalité des projets de normes C ++, et un certain nombre de compilateurs l'ont fait (pas seulement les compilateurs Microsoft). De mémoire, il a été modifié dans un projet vers 1995 pour rendre la variable locale à la boucle - environ trois ans avant la ratification de la première norme C ++. Ainsi, la plupart des compilateurs C ++ antérieurs à (environ) 1996 fonctionnaient de cette façon.
Peter

15

{et }créera une portée et si vous définissez certaines variables dans la portée, vous ne pouvez pas y accéder de l'extérieur. Mais forcréez déjà cette portée. Alors

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

est le même que

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

mais si vous définissez quelque chose entre eux, il y a une différence

{int a = 0; for(int i = 0; i < count; ++i){}}

Dans cet exemple, ane sera pas accessible de l'extérieur de la portée.


2

Dans votre exemple particulier, il n'y a aucune raison pour eux.

Parfois, vous pouvez créer une étendue pour une variable:

float average;
// ...

{
int sum = 0;
for (int i = 0; i < count; ++i)
{
   sum += v[i];
}
average = (float)sum / count;
}

// use average
// sum not in scope here

Cependant, je vois cela comme un anti-modèle. Habituellement, si vous avez besoin de faire cela, cela devrait probablement forêtre sa propre fonction.


D'accord, si vous pensez que cela devrait être dans sa propre fonction (je peux penser à de nombreuses fois où cela ne ferait qu'au moins ajouter des frais généraux, mais je ne vais pas y aller) une question hypothétique pour vous: qu'en est-il si vous avez besoin d'un portée locale spécifique à un boîtier de commutation? Il y a certainement des moments où l'ajout d'une portée supplémentaire (ce que fait bien sûr une fonction aussi) (notez que pour votre exemple, je ne pense pas du tout qu'une fonction séparée est une mauvaise idée) est inutile, mais d'autres fois ce n'est pas si simple même si il existe d'autres moyens.
Pryftan

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.