November 23, 2020

Цикл for range-based

В С++ существует три основных цикла: while, do...while и for. В С++11 добавили новый тип цикла for range-based (цикл, основанный на диапазоне). Этот цикл предоставляет более простой и безопасный способ итерации по массиву или другому контейнеру.

Синтаксис цикла for range-based следующий:

for (объявление_элемента : массив)
стейтмент;

Выполняется итерация по каждому элементу массива, присваивая значение текущего элемента массива переменной, объявленной как элемент. Рассмотрим пример:

int main() {
    int math[] = { 0, 1, 4, 5, 7, 8, 10, 12, 15, 17, 30, 41};
    for (int number : math) 
        cout << number << ' ';
}    
    
// Вывод: 0 1 4 5 7 8 10 12 15 17 30 41

При выполнении цикла переменной numberприсваивается значение первого элемента (т.е. значение 0). Дальше программа выполняет вывод значения переменной number. Затем цикл for выполняется снова, и значением переменной number уже является 1 (второй элемент массива). Вывод значения number выполняется снова. Цикл продолжает свое выполнение до тех пор, пока в массиве не останется непройденных элементов.

Обратите внимание, переменная number не является индексом массива. Ей просто присваивается значение элемента массива в текущей итерации цикла.

Поскольку объявляемый элемент цикла должен быть того же типа, что и элементы массива, то можно использовать ключевого слова auto, когда мы позволяем C++ вычислить тип данных элементов массива вместо нас. Например:

int main() {
    int math[] = { 0, 1, 4, 5, 7, 8, 10, 12, 15, 17, 30, 41};
    for (auto number : math) 
        cout << number << ' ';
}  

Каждый обработанный элемент массива копируется в переменную number. Это копирование может оказаться затратным, в большинстве случаев мы можем просто ссылаться на исходный элемент с помощью ссылки. Конечно же, хорошей идеей будет сделать объявляемый элемент константным, тогда вы сможете его использовать в режиме «только для чтения»:

int main() {
    int math[] = { 0, 1, 4, 5, 7, 8, 10, 12, 15, 17, 30, 41};
    for (const auto &number : math) 
        cout << number << ' ';
}  

Поэтому в целях улучшения производительности используйте обычные ссылки или константные ссылки в качестве объявляемого элемента в цикле for range-based.

Циклы for range-based не предоставляют прямой способ получения индекса текущего элемента массива. Это связано с тем, что большинство структур, с которыми могут использоваться эти циклы, напрямую не индексируются!

Заключение

Циклы for range-based обеспечивают лучший синтаксис для итерации по массиву, когда нам нужно получить доступ ко всем элементам массива в последовательном порядке. Эти циклы предпочтительнее использовать вместо стандартных циклов for в случаях, когда они могут использоваться. Для предотвращения создания копий каждого элемента в качестве объявляемого элемента следует использовать ссылку.