Цикл For внутри фигурных скобок

117

Я наткнулся на этот макет цикла:

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

Мне было интересно, для чего нужен этот дополнительный слой подтяжек? Это несколько раз появляется в нашей кодовой базе.

Эд Норман
источник
47
Они совершенно излишни в опубликованном вами фрагменте кода
EdChum
25
какие компиляторы использовались с этим кодом? Конкретно VS 6 прижился?
UKMonkey
5
@EdNorman теперь с вашим редактированием стало намного понятнее. Кажется, что правильный ответ дает UKMonkey. С помощью современного компилятора C ++ вы можете просто удалить фигурные скобки.
Jabberwocky
8
В качестве альтернативы, это может быть сгенерированный код (вздохнул кто-то, только начинающий
разбираться в
4
Одна из возможных причин заключается в том, что в коде когда-то были (или предполагается, что в будущем) параллельные директивы OpenMP.
jamesqf

Ответы:

286

Давным-давно, много лун назад, VS6 существовал и был популярен. Однако он не соответствовал ряду стандартов C ++; что было разумным в то время, поскольку он был выпущен незадолго до (в том же году) официального выпуска стандарта; однако, насколько мне известно, он придерживался проекта стандарта.

Одним из стандартов, которые изменились между черновиком и официальным стандартом, было время жизни переменных цикла for, созданных в первом разделе; что приводит к тому, что следующий код не может быть скомпилирован

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

потому что iбыл переопределен вторым циклом for.

В то время как другие компиляторы также страдали этой ошибкой; Я выделяю версию VS6, потому что она оставалась единственной версией Visual Studio в течение нескольких лет после выпуска стандарта, но никогда не выпускала обновления для этой конкретной проблемы; это означает, что это имело более значительное влияние.

Чтобы решить эту проблему, нужно поместить весь цикл for в его собственную область видимости, как вы показали.

UKMonkey
источник
49
Не нужно искать VS6, чтобы увидеть этот @bolov, установите "Force Conformance in For Loop Scope" на "No" в VS2015 и наслаждайтесь ;-)
alain
5
@alain "опция" Zc: forScope- "устарела и будет удалена в следующем выпуске" и компилируется без проблем ... Мне грустно,
bolov
7
GCC до версии 2.7 также демонстрировал такое поведение. См. Docs.freebsd.org/info/g++FAQ/g++FAQ.info.for_scope.html
Джереми,
5
@Damon этого не было, когда VS6 был впервые выпущен; однако, когда стандарты изменились, соответствующее им обновление так и не было выпущено. VS6 оставался популярным в течение нескольких лет после изменения стандартов.
UKMonkey
7
Приписывать это греху старого компилятора Microsoft - подделка. Такое поведение на самом деле было особенностью черновиков стандартов C ++, и это было сделано рядом компиляторов (не только компиляторов Microsoft). По памяти, примерно в 1995 году в черновике его изменили, чтобы сделать переменную локальной для цикла - примерно за три года до ратификации первого стандарта C ++. Таким образом, большинство компиляторов C ++ до (примерно) 1996 года работали именно так.
Питер
15

{и }создаст область, и если вы определите некоторые переменные в области, вы не сможете получить к ним доступ извне. Но forуже создайте этот размах. Так

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

такой же как

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

но если вы определите что-то между ними, есть разница

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

В этом примере aнедоступен извне.

cokceken
источник
2

В вашем конкретном примере для них нет причин.

Иногда вам может понадобиться создать область для переменной:

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

Однако я вижу в этом антипаттерны. Обычно, если вам нужно это сделать, то, скорее всего, это forдолжно быть отдельной функцией.

Болов
источник
Хорошо, если вы думаете, что это должно быть в своей собственной функции (я могу вспомнить много раз, когда это только добавило бы накладных расходов, по крайней мере, но я не собираюсь туда идти), гипотетический вопрос для вас: как насчет того, если вам понадобится конкретный локальный охват к корпусу коммутатора? Конечно, бывают случаи, когда добавление дополнительной области (что, конечно, делает и функция) (обратите внимание, что в вашем примере я вообще не думаю, что отдельная функция - плохая идея) не нужно, но в других случаях это не так просто, даже если есть и другие способы.
Pryftan