for
loop
Условно выполняет оператор повторно, при этом оператору не требуется управлять условием цикла.
Содержание |
Синтаксис
attr
(необязательно)
for (
init-statement
condition
(необязательно)
;
expression
(необязательно)
)
statement
|
|||||||||
| attr | - | (since C++11) любое количество attributes | ||
| init-statement | - |
один из
Обратите внимание, что любой init-statement должен заканчиваться точкой с запятой. Поэтому его часто неформально описывают как выражение или объявление, за которым следует точка с запятой. |
||
| condition | - | condition | ||
| expression | - | expression (обычно выражение, увеличивающее счётчик цикла) | ||
| statement | - | statement (обычно составной оператор) |
Условие
Условием может быть либо condition , либо expression , либо simple declaration .
|
(since C++26) |
- Если это может быть синтаксически разрешено как выражение, оно трактуется как выражение. В противном случае оно трактуется как объявление которое не является объявлением структурированной привязки (начиная с C++26) .
Когда управление достигает условия, условие даёт значение, которое используется для определения, будет ли statement выполнена.
Выражение
Если condition является выражением, возвращаемое им значение — это значение выражения, контекстно преобразованное в bool . Если это преобразование некорректно, программа является некорректной.
Объявление
Если condition является простым объявлением, возвращаемое значение - это значение переменной решения (см. ниже), контекстно преобразованное в bool . Если это преобразование некорректно, программа является некорректной.
Объявление без структурированной привязки
Объявление имеет следующие ограничения:
- Синтаксически соответствует следующей форме:
|
(до C++11) |
|
(начиная с C++11) |
- Декларатор не может определять функцию или массив .
- последовательность спецификаторов типа (до C++11) последовательность спецификаторов объявления может содержать только спецификаторы типа и constexpr , и она (начиная с C++11) не может определять класс или перечисление .
Переменная решения объявления - это объявленная переменная.
Объявление структурированной привязкиОбъявление имеет следующие ограничения:
Переменной решения объявления является введённая переменная e введённая объявлением . |
(начиная с C++26) |
Объяснение
Оператор for эквивалентный:
{
|
|||||||||
За исключением того, что
- Область видимости init-statement и область видимости condition совпадают.
- Область видимости statement и область видимости expression не пересекаются и вложены в область видимости init-statement и condition .
- Выполнение continue statement в statement приведет к вычислению expression .
- Пустой condition эквивалентен true .
Если цикл необходимо прервать внутри statement , в качестве завершающей инструкции можно использовать break statement .
Если текущую итерацию необходимо прервать внутри statement , в качестве сокращения можно использовать continue statement .
Примечания
Как и в случае с
while
циклом, если
statement
не является составным оператором, область видимости переменных, объявленных в нём, ограничивается телом цикла, как если бы это был составной оператор.
for (;;) int n; // n выходит из области видимости
В рамках гарантии прогресса C++ поведение является неопределённым , если цикл не являющийся тривиальным бесконечным циклом (начиная с C++26) без наблюдаемого поведения не завершается. Компиляторам разрешено удалять такие циклы.
В то время как в C имена, объявленные в области видимости init-statement и condition , могут быть переопределены в области видимости statement , в C++ это запрещено:
for (int i = 0;;) { long i = 1; // корректно в C, некорректно в C++ // ... }
Ключевые слова
Пример
#include <iostream> #include <vector> int main() { std::cout << "1) типичный цикл с одним оператором в теле:\n"; for (int i = 0; i < 10; ++i) std::cout << i << ' '; std::cout << "\n\n" "2) init-statement может объявлять несколько имён,\n" "если они используют одинаковый decl-specifier-seq:\n"; for (int i = 0, *p = &i; i < 9; i += 2) std::cout << i << ':' << *p << ' '; std::cout << "\n\n" "3) условие может быть объявлением:\n"; char cstr[] = "Hello"; for (int n = 0; char c = cstr[n]; ++n) std::cout << c; std::cout << "\n\n" "4) init-statement может использовать спецификатор типа auto:\n"; std::vector<int> v = {3, 1, 4, 1, 5, 9}; for (auto iter = v.begin(); iter != v.end(); ++iter) std::cout << *iter << ' '; std::cout << "\n\n" "5) init-statement может быть выражением:\n"; int n = 0; for (std::cout << "Начало цикла\n"; std::cout << "Проверка цикла\n"; std::cout << "Итерация " << ++n << '\n') { if (n > 1) break; } std::cout << "\n" "6) конструкторы и деструкторы объектов, созданных\n" "в теле цикла, вызываются на каждой итерации:\n"; struct S { S(int x, int y) { std::cout << "S::S(" << x << ", " << y << "); "; } ~S() { std::cout << "S::~S()\n"; } }; for (int i{0}, j{5}; i < j; ++i, --j) S s{i, j}; std::cout << "\n" "7) init-statement может использовать structured bindings:\n"; long arr[]{1, 3, 7}; for (auto [i, j, k] = arr; i + j < k; ++i) std::cout << i + j << ' '; std::cout << '\n'; }
Вывод:
1) типичный цикл с одним оператором в теле: 0 1 2 3 4 5 6 7 8 9 2) init-statement может объявлять несколько имён, если они используют одинаковый decl-specifier-seq: 0:0 2:2 4:4 6:6 8:8 3) условие может быть объявлением: Hello 4) init-statement может использовать спецификатор типа auto: 3 1 4 1 5 9 5) init-statement может быть выражением: Начало цикла Проверка цикла Итерация 1 Проверка цикла Итерация 2 Проверка цикла 6) конструкторы и деструкторы объектов, созданных в теле цикла, вызываются на каждой итерации: S::S(0, 5); S::~S() S::S(1, 4); S::~S() S::S(2, 3); S::~S() 7) init-statement может использовать structured bindings: 4 5 6
Смотрите также
цикл
for
по диапазону
(C++11)
|
выполняет цикл по диапазону |
|
документация C
для
for
|
|