<MyRusakov.ru />

Профессиональная Web-разработка. Дизайн, код и автоматизация

Профессиональная Web-разработка. Дизайн, код и автоматизация

Это очень подробный курс из разряда "всё включено". Разбираются следующие темы: HTML, CSS, SCSS, JavaScript, PHP, SQL, Laravel, Nginx, PostCSS, npm, Vite, Vitest, Composer, PHPUnit, Prettier, Stylelint, ESLint, Pint, Larastan, Git, Agile, Scrum, Docker, Supervisord, Figma, Stitch AI, Confluence, Jira.

Рассчитан и на новичков, и на тех, кто уже знаком с основами, но хочет освоить полный цикл разработки.

Помимо самой теории, Вы увидите пример создания Web-проекта на 20 000 строк кода: от идеи и документации на Confluence через планирование на Jira, fullstack-разработку до деплоя на VPS.

Помимо уроков, курс содержит упражнения для закрепления знаний и финальное тестирование. А ещё Вы получите 5 полноценных Бонусных курсов: «GitLab под ключ», «Вёрстка сайта с нуля 2.0», «JavaScript с Нуля до Гуру 2.0», «PHP и MySQL с Нуля до Гуру 3.0» и «Laravel от А до Я».

Подробнее
Подписка

Подпишитесь на мой канал на YouTube, где я регулярно публикую новые видео.

YouTube Подписаться

Подписавшись по E-mail, Вы будете получать уведомления о новых статьях.

Подписка Подписаться

Добавляйтесь ко мне в друзья ВКонтакте! Отзывы о сайте и обо мне оставляйте в моей группе.

Мой аккаунт Мой аккаунт Моя группа
Опрос

Какая тема Вас интересует больше?

Range-based for в C++: удобный перебор контейнеров без ошибок индексов

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&, а обычный цикл с индексом оставляйте для ситуаций, где индекс действительно нужен.

Копирование материалов разрешается только с указанием автора (Михаил Русаков) и индексируемой прямой ссылкой на сайт (https://myrusakov.ru)!

Добавляйтесь ко мне в друзья ВКонтакте: https://vk.com/myrusakov.
Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: https://vk.com/rusakovmy.

Если Вы не хотите пропустить новые материалы на сайте,
то Вы можете подписаться на обновления: Подписаться на обновления

Если у Вас остались какие-либо вопросы, либо у Вас есть желание высказаться по поводу этой статьи, то Вы можете оставить свой комментарий внизу страницы.

Порекомендуйте эту статью друзьям:

Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):

  1. Кнопка:

    Она выглядит вот так: Как создать свой сайт

  2. Текстовая ссылка:

    Она выглядит вот так: Как создать свой сайт

  3. BB-код ссылки для форумов (например, можете поставить её в подписи):

Комментарии (0):

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