Loop For dentro de suas próprias chaves


117

Eu encontrei este layout for-loop:

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

Eu queria saber para que serve essa camada extra de colchetes? Isso aparece algumas vezes em nossa base de código.


47
Eles são completamente supérfluos no snippet de código que você postou
EdChum

25
quais compiladores foram usados ​​com este código? Especificamente, o VS 6 foi usado?
UKMonkey

5
@EdNorman agora com sua edição é muito mais claro. Parece que a resposta correta é a fornecida pelo UKMonkey. Com o compilador C ++ moderno, você pode simplesmente eliminar as chaves.
Jabberwocky

8
Alternativamente, poderia ser código gerado (suspirou alguém acabando de se familiarizar com Rhapsody)
Mawg diz reintegrar Monica

4
Uma possível razão é se o código já teve (ou pretende ter no futuro) diretivas paralelas OpenMP.
jamesqf

Respostas:


286

Era uma vez, muitas luas atrás, VS6 existia e era popular. No entanto, ele falhou em estar de acordo com vários padrões C ++; o que era razoável na época, pois foi lançado um pouco antes (no mesmo ano) do padrão ser oficialmente lançado; no entanto, aderiu ao rascunho da norma, tanto quanto eu sei.

Um dos padrões que mudou entre o rascunho e o padrão oficial foi o tempo de vida das variáveis ​​de loop for criadas na primeira seção; levando à falha de compilação do código a seguir

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

porque ifoi redefinido pelo segundo loop for.

Enquanto outros compiladores também sofreram esse bug; Destaco o VS6 porque ele permaneceu a única versão do Visual Studio por vários anos após o lançamento do padrão, mas nunca lançou uma atualização para este problema específico; o que significa que teve um impacto mais significativo.

Uma solução para isso é forçar todo o loop for em seu próprio escopo, como você mostrou.


49
Não há necessidade de encontrar VS6 para ver que @bolov, defina "Force Conformance in For Loop Scope" para "No" em VS2015 e aproveite ;-)
alain

5
@alain "a opção 'Zc: forScope-' tornou-se obsoleta e será removida em uma versão futura" e compila sem problemas ... Estou triste
bolov

7
O GCC anterior à versão 2.7 também exibia esse comportamento. Consulte docs.freebsd.org/info/g++FAQ/g++FAQ.info.for_scope.html
Jeremy

5
@Damon não era quando o VS6 foi lançado pela primeira vez; no entanto, quando os padrões mudaram, uma atualização em conformidade com eles nunca foi lançada. O VS6 permaneceu popular por alguns anos depois que os padrões foram alterados.
UKMonkey

7
Atribuir isso a um pecado de um compilador antigo da Microsoft é falso. Esse comportamento era, na verdade, um recurso dos rascunhos dos padrões C ++, e vários compiladores fizeram isso (não apenas os compiladores da Microsoft). De memória, ele foi alterado em um rascunho durante cerca de 1995 para tornar a variável local para o loop - cerca de três anos antes de o primeiro padrão C ++ ser ratificado. Portanto, a maioria dos compiladores C ++ anteriores a (cerca de) 1996 funcionavam dessa forma.
Peter,

15

{e }criará um escopo e, se você definir algumas variáveis ​​no escopo, não poderá acessá-las de fora. Mas forjá crie esse escopo. assim

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

é o mesmo que

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

mas se você definir algo entre eles, há uma diferença

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

Neste exemplo, anão estará acessível de fora do escopo.


2

Em seu exemplo particular, não há razão para eles.

Às vezes, você pode querer criar um escopo para uma variável:

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

No entanto, vejo isso como um antipadrão. Normalmente, se você precisar fazer isso, provavelmente o fordeve ser uma função própria.


Ok, se você acha que deveria estar em sua própria função (posso pensar em muitas vezes em que isso apenas aumentaria a sobrecarga, mas não irei lá) uma pergunta hipotética para você: e se você precisar de um escopo local específico para um caso de switch? Certamente há momentos em que adicionar um escopo adicional (que, claro, uma função também faz) (observe que, para o seu exemplo, eu não acho que uma função separada seja uma má ideia) é desnecessário, mas outras vezes não é tão simples, mesmo que existem outras maneiras.
Pryftan de

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.