Do pętli wewnątrz własnych nawiasów klamrowych

117

Natknąłem się na ten układ 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;
}

Zastanawiałem się, do czego służy ta dodatkowa warstwa szelek? To pojawia się kilka razy w naszej bazie kodu.

Ed Norman
źródło
47
Są całkowicie zbędne we fragmencie kodu, który opublikowałeś
EdChum
25
jakie kompilatory zostały użyte z tym kodem? W szczególności, czy VS 6 został użyty?
UKMonkey
5
@EdNorman teraz z twoją edycją jest znacznie jaśniejszy. Wydaje się, że prawidłowa odpowiedź to ta, której udzielił UKMonkey. Dzięki nowoczesnemu kompilatorowi C ++ możesz po prostu usunąć nawiasy klamrowe.
Jabberwocky
8
Alternatywnie, może to być wygenerowany kod (westchnął ktoś, kto właśnie
próbuje uporać się
4
Jednym z możliwych powodów jest to, że kod miał kiedyś (lub ma mieć w przyszłości) dyrektywy równoległe OpenMP.
jamesqf

Odpowiedzi:

286

Dawno, dawno temu, wiele księżyców temu VS6 istniał i był popularny. Jednak nie był zgodny z wieloma standardami C ++; co było rozsądne w tamtym czasie, ponieważ został wydany tuż przed (w tym samym roku) oficjalnym wydaniem standardu; był jednak zgodny z projektem standardu, o ile wiem.

Jednym ze standardów, który zmienił się między wersją roboczą a oficjalną normą, był czas życia zmiennych pętli for utworzonych w pierwszej sekcji; co prowadzi do niepowodzenia kompilacji następującego kodu

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

ponieważ izostała przedefiniowana przez drugą pętlę for.

Podczas gdy inne kompilatory również miały ten błąd; Podkreślam wersję VS6, ponieważ pozostawała jedyną wersją Visual Studio przez wiele lat po wydaniu standardu, ale nigdy nie wydała aktualizacji dla tego konkretnego wydania; co oznacza, że ​​miał bardziej znaczący wpływ.

Rozwiązaniem tego problemu jest wymuszenie całej pętli for we własnym zakresie, jak pokazano.

UKMonkey
źródło
49
Nie trzeba szukać VS6, żeby zobaczyć to @bolov, ustaw "Force Conformance in For Loop Scope" na "No" w VS2015 i ciesz się ;-)
alain
5
@alain "opcja 'Zc: forScope-' została wycofana i zostanie usunięta w przyszłym wydaniu" i kompiluje się bez problemu ... Przykro mi
bolov
7
GCC przed wersją 2.7 również wykazywało takie zachowanie. Zobacz docs.freebsd.org/info/g++FAQ/g++FAQ.info.for_scope.html
Jeremy
5
@Damon nie było, kiedy VS6 został wydany po raz pierwszy; Jednak gdy standardy uległy zmianie, zgodna z nimi aktualizacja nigdy nie została wydana. VS6 pozostał popularny przez dobre kilka lat po zmianie standardów.
UKMonkey
7
Przypisywanie tego do grzechu starego kompilatora Microsoftu jest fałszywe. To zachowanie było w rzeczywistości cechą szkicowych standardów C ++ i zrobiło to wiele kompilatorów (nie tylko kompilatory Microsoft). Z pamięci zmieniono go w wersji roboczej około 1995 roku, aby uczynić zmienną lokalną dla pętli - około trzy lata przed ratyfikacją pierwszego standardu C ++. Więc większość kompilatorów C ++ sprzed (około) 1996 roku działała w ten sposób.
Peter
15

{i }utworzy zakres, a jeśli zdefiniujesz niektóre zmienne w zakresie, nie będziesz mieć do nich dostępu z zewnątrz. Ale forjuż stwórz ten zakres. Więc

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

jest taki sam jak

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

ale jeśli zdefiniujesz coś między nimi, jest różnica

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

W tym przykładzie anie będzie dostępny z zewnątrz.

cokceken
źródło
2

W twoim konkretnym przykładzie nie ma dla nich żadnego powodu.

Czasami możesz chcieć utworzyć zakres dla zmiennej:

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

Jednak widzę to jako anty-wzór. Zwykle, jeśli potrzebujesz tego zrobić, najprawdopodobniej forpowinno to być jego własną funkcją.

bolov
źródło
W porządku, jeśli uważasz, że powinno to działać w swojej własnej funkcji (mogę pomyśleć o wielu przypadkach, w których co najmniej zwiększyłoby to tylko narzut, ale nie zamierzam tam iść) hipotetyczne pytanie do ciebie: a co jeśli potrzebujesz konkretny zakres lokalny do przypadku przełącznika? Z pewnością zdarzają się sytuacje, w których dodanie dodatkowego zakresu (co oczywiście robi również funkcja) (zauważ, że dla twojego przykładu nie sądzę, aby oddzielna funkcja była złym pomysłem) jest niepotrzebne, ale innym razem nie jest to takie proste, nawet jeśli są inne sposoby.
Pryftan,
2

Jest to zakres blokowy oznaczony {}nawiasami klamrowymi. Zwykle służy do oznaczenia obszaru automatycznego składowania . W twoim przypadku wydaje się, że nic nie robi, ponieważ pętla for ma swój własny zakres w standardowym C ++.

Ron
źródło