Expressions and statements
ES.71
Предпочитайте range-`for` обычному `for`, когда есть выбор
Причина
Читаемость. Предотвращение ошибок. Эффективность.
Пример
for (gsl::index i = 0; i < v.size(); ++i) // плохо
cout << v[i] << '\n';
for (auto p = v.begin(); p != v.end(); ++p) // плохо
cout << *p << '\n';
for (auto& x : v) // OK
cout << x << '\n';
for (gsl::index i = 1; i < v.size(); ++i) // обращение к двум элементам: нельзя использовать range-for
cout << v[i] + v[i - 1] << '\n';
for (gsl::index i = 0; i < v.size(); ++i) // возможный побочный эффект: нельзя использовать range-for
cout << f(v, &v[i]) << '\n';
for (gsl::index i = 0; i < v.size(); ++i) { // тело модифицирует переменную цикла: нельзя использовать range-for
if (i % 2 != 0)
cout << v[i] << '\n'; // вывести нечётные элементы
}
Человек или хороший статический анализатор может определить, что в f(v, &v[i]) нет побочного эффекта на v, и цикл можно переписать.
«Вмешательство в переменную цикла» в теле цикла обычно лучше избегать.
Примечание
Не используйте дорогостоящее копирование переменной цикла в range-for:
for (string s : vs) // ...
Это скопирует каждый элемент vs в s. Лучше:
for (string& s : vs) // ...
Ещё лучше, если переменная цикла не изменяется и не копируется:
for (const string& s : vs) // ...
Контроль
Проверять циклы: если традиционный цикл просто перебирает элементы последовательности без побочных эффектов — переписать как range-for.