Range-based for в C++: удобный перебор контейнеров без ошибок индексов
Поисковый запрос «range based for C++ примеры» часто возникает у тех, кто уже знает обычный цикл for, но хочет писать код короче и безопаснее. Range-based for, или цикл по диапазону, появился в C++11 и стал стандартным способом обхода массивов, строк и контейнеров STL.
Что такое range-based for
Range-based for позволяет пройти по всем элементам диапазона без явного индекса. Базовый синтаксис выглядит так:
for (тип переменная : контейнер) {
// работа с переменной
}
Например, выведем элементы вектора:
#include <iostream>
#include <vector>
int main() {
std::vector<int> numbers = {10, 20, 30, 40};
for (int x : numbers) {
std::cout << x << ' ';
}
}
Такой код легче читать: сразу понятно, что мы обходим все элементы numbers.
Используйте auto, чтобы не дублировать тип
В реальном коде тип элемента может быть длинным: std::string, std::pair<...>, пользовательский класс. Поэтому часто используют auto:
#include <iostream>
#include <string>
#include <vector>
int main() {
std::vector<std::string> names = {"Анна", "Игорь", "Мария"};
for (auto name : names) {
std::cout << name << '\n';
}
}
Но здесь есть важный нюанс: auto name создаёт копию каждого элемента. Для чисел это обычно не страшно, а для строк и объектов может быть лишней тратой ресурсов.
auto& и const auto&: когда нужны ссылки
Если вы хотите только читать элементы и не копировать их, используйте const auto&:
for (const auto& name : names) {
std::cout << name << '\n';
}
Это один из самых полезных шаблонов для повседневного C++: он не копирует объект и не позволяет случайно изменить контейнер.
Если же элементы нужно изменить, используйте auto&:
#include <iostream>
#include <vector>
int main() {
std::vector<int> scores = {7, 8, 9};
for (auto& score : scores) {
score += 1;
}
for (const auto& score : scores) {
std::cout << score << ' ';
}
}
Результат будет 8 9 10. Если бы мы написали auto score, изменялась бы только копия, а исходный вектор остался бы прежним.
Range-based for со строками и массивами
Цикл по диапазону работает не только с std::vector. Например, можно перебрать символы строки:
#include <iostream>
#include <string>
int main() {
std::string word = "cpp";
for (char ch : word) {
std::cout << ch << '\n';
}
}
Также он подходит для обычных массивов, если размер массива известен компилятору:
int values[] = {1, 2, 3, 4};
for (int value : values) {
std::cout << value << ' ';
}
Это удобнее и безопаснее, чем вручную писать границы цикла и рисковать ошибкой в индексе.
Перебор std::map и structured bindings
Для ассоциативных контейнеров range-based for особенно удобен. В C++17 можно использовать структурные привязки:
#include <iostream>
#include <map>
#include <string>
int main() {
std::map<std::string, int> ages = {
{"Анна", 25},
{"Игорь", 31}
};
for (const auto& [name, age] : ages) {
std::cout << name << ": " << age << '\n';
}
}
Без структурных привязок пришлось бы обращаться к pair.first и pair.second, что менее читаемо.
Когда обычный for всё ещё лучше
Range-based for хорош, когда нужно пройти по всем элементам. Но обычный цикл с индексом полезнее, если:
- нужен номер текущего элемента;
- нужно идти не по всем элементам, а с шагом;
- требуется обход в обратном порядке;
- нужно сравнивать текущий элемент с соседними.
std::vector<int> numbers = {5, 10, 15};
for (std::size_t i = 0; i < numbers.size(); ++i) {
std::cout << "index=" << i
<< ", value=" << numbers[i] << '\n';
}
Главная рекомендация: если индекс не нужен — выбирайте range-based for.
Типичные ошибки новичков
Ошибка 1: пытаться изменить элементы без ссылки.
for (auto x : numbers) {
x *= 2; // меняется копия, а не элемент вектора
}
Правильно так:
for (auto& x : numbers) {
x *= 2;
}
Ошибка 2: копировать тяжёлые объекты. Для строк, структур и классов чаще используйте const auto&, если не планируете менять элементы.
Ошибка 3: изменять размер контейнера во время обхода. Например, добавлять элементы в std::vector внутри range-based for опасно: ссылки и итераторы могут стать недействительными.
// Плохая идея
for (auto x : numbers) {
numbers.push_back(x); // может привести к неожиданному поведению
}
Если нужно добавлять или удалять элементы, лучше заранее продумать алгоритм: создать новый контейнер, использовать индексы или подходящие STL-алгоритмы.
Практические рекомендации
- Для простых чисел можно писать auto x.
- Для чтения объектов используйте const auto& x.
- Для изменения элементов используйте auto& x.
- Не меняйте размер контейнера внутри range-based for без необходимости.
- Если нужен индекс, используйте обычный for.
Если вы хотите уверенно разобраться не только с циклами, но и с контейнерами STL, функциями, классами и современными возможностями языка, посмотрите пошаговый курс «Программирование на C++ с Нуля до Гуру» — он хорошо подходит для системного изучения C++ с практикой.
Итог
Range-based for в C++ делает перебор контейнеров короче, безопаснее и понятнее. В большинстве случаев для чтения элементов выбирайте const auto&, для изменения — auto&, а обычный цикл с индексом оставляйте для ситуаций, где индекс действительно нужен.
-
Создано 21.09.2026 17:01:28
-
Михаил Русаков

Комментарии (0):
Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.