Para bucle dentro de sus propias llaves

117

Me he encontrado con este diseño de bucle for:

#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;
}

Me preguntaba para qué es esta capa adicional de aparatos ortopédicos. Esto aparece varias veces en nuestra base de código.

Ed Norman
fuente
47
Son completamente superfluos en el fragmento de código que publicó
EdChum
25
¿Qué compiladores se han utilizado con este código? Específicamente, ¿se usó VS 6?
UKMonkey
5
@EdNorman ahora con su edición es mucho más claro. Parece que la respuesta correcta es la proporcionada por UKMonkey. Con el compilador moderno de C ++, puede simplemente eliminar las llaves.
Jabberwocky
8
Alternativamente, podría ser un código generado (suspiró alguien que acaba de enfrentarse a Rhapsody)
Mawg dice reinstalar a Monica
4
Una posible razón es si el código alguna vez tuvo (o pretende tener en el futuro) directivas paralelas de OpenMP.
jamesqf

Respuestas:

286

Érase una vez, hace muchas lunas, VS6 existía y era popular. Sin embargo, falló en ajustarse a varios estándares de C ++; lo cual era razonable en ese momento, ya que fue lanzado justo antes (el mismo año) que el estándar fue lanzado oficialmente; sin embargo, se adhirió al borrador de la norma que yo sepa.

Uno de los estándares que cambió entre el borrador y el estándar oficial fue la vida útil de las variables del ciclo for creadas en la primera sección; lo que provoca que el siguiente código no se compile

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

porque ifue redefinido por el segundo bucle for.

Mientras que otros compiladores también sufrieron este error; Destaco el VS6 porque siguió siendo la única versión de Visual Studio durante varios años después del lanzamiento del estándar, pero nunca lanzó una actualización para este problema en particular; lo que significa que tuvo un impacto más significativo.

Una solución a esto es forzar todo el bucle for a su propio alcance, como ha mostrado.

Reino UnidoMono
fuente
49
No es necesario encontrar VS6 para ver que @bolov, establezca "Forzar conformidad en el alcance del bucle" en "No" en VS2015 y disfrute ;-)
alain
5
@alain "La opción 'Zc: forScope-' ha quedado obsoleta y se eliminará en una versión futura" y se compila sin problemas ... Estoy triste
bolov
7
GCC antes de la versión 2.7 también exhibió este comportamiento. Ver docs.freebsd.org/info/g++FAQ/g++FAQ.info.for_scope.html
Jeremy
5
@Damon no lo era cuando se lanzó VS6 por primera vez; sin embargo, cuando los estándares cambiaron, nunca se lanzó una actualización que los cumpliera. VS6 siguió siendo popular durante unos años después de que se cambiaron los estándares.
UKMonkey
7
Atribuir esto a un pecado de un viejo compilador de Microsoft es falso. Este comportamiento era en realidad una característica de los borradores de estándares C ++, y varios compiladores lo hicieron (no solo los compiladores de Microsoft). Desde la memoria, se cambió en un borrador durante aproximadamente 1995 para hacer que la variable sea local en el bucle, aproximadamente tres años antes de que se ratificara el primer estándar C ++. Así que la mayoría de los compiladores de C ++ anteriores a (aproximadamente) 1996 funcionaron de esta manera.
Peter
15

{y }creará un alcance y si define algunas variables en el alcance, no podrá acceder a ellas desde fuera. Pero forya crea ese alcance. Entonces

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

es lo mismo que

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

pero si defines algo entre ellos, hay una diferencia

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

En este ejemplo, ano será accesible desde fuera del alcance.

cokceken
fuente
2

En su ejemplo particular, no hay razón para ellos.

A veces, es posible que desee crear un alcance para una 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

Sin embargo, veo esto como un anti-patrón. Por lo general, si necesita hacer esto, lo más probable es forque sea su propia función.

bolov
fuente
De acuerdo, si crees que debería estar en su propia función (puedo pensar en muchas ocasiones en las que eso solo agregaría gastos generales al menos, pero no voy a ir allí) una pregunta hipotética para ti: ¿qué pasa si necesitas un alcance local específico a un caso de interruptor? Ciertamente, hay ocasiones en las que agregar un alcance adicional (que, por supuesto, una función también lo hace) (tenga en cuenta que para su ejemplo, no creo que una función separada sea una mala idea) es innecesario, pero otras veces no es tan simple, incluso si hay otras formas.
Pryftan