Что такое forward_iterator в C++?

Ответ

Forward iterator (однонаправленный итератор) — это одна из категорий итераторов в C++, которая расширяет возможности input_iterator и output_iterator. Он гарантирует возможность многократного прохода по одному и тому же диапазону и сохранение валидности других итераторов на ту же последовательность при инкременте.

Требования (концепт std::forward_iterator с C++20):

  • Поддерживает чтение (*it) и запись (*it = value) (если не константный).
  • Допускает инкремент (++it, it++).
  • Многопроходность: диапазон можно проходить несколько раз.
  • Стабильность ссылок: значение, полученное разыменованием, остаётся валидным до тех пор, пока итератор не инвалидируется другими операциями (например, удалением элемента).
  • Поддерживает сравнение на равенство/неравенство (==, !=).

Контейнеры, использующие forward iterators:

  • std::forward_list
  • std::unordered_set, std::unordered_multiset
  • std::unordered_map, std::unordered_multimap

Пример с std::forward_list:

#include <forward_list>
#include <iostream>

int main() {
    std::forward_list<int> flist = {10, 20, 30, 40};

    // forward_iterator позволяет проходить по списку только вперёд
    for (auto it = flist.begin(); it != flist.end(); ++it) {
        std::cout << *it << ' '; // Чтение
        *it += 5;                // Запись (изменение значения)
    }
    std::cout << 'n';

    // Многопроходность: можно снова пройти по тому же диапазону
    for (const auto& val : flist) {
        std::cout << val << ' '; // Выведет: 15 25 35 45
    }
    return 0;
}

Отличие от более мощных итераторов: Forward iterator не поддерживает декремент (--) и арифметику указателей (произвольный доступ), в отличие от bidirectional_iterator (например, у std::list) и random_access_iterator (например, у std::vector).

Ответ 18+ 🔞

Слушай, а вот forward iterator — это такая штука, которая как будто тебе дали одноразовую зажигалку, а ты её можешь чиркать дохуя раз, но только вперёд. В рот мне чих-пых, понимаешь? Он берёт всё от input и output итераторов, но ещё и гарантирует, что если ты прошёл по списку, то можешь вернуться в начало и пройти ещё раз — и ничего не разъёбется. И другие итераторы на эту же коллекцию не накроются медным тазом, пока ты одного из них инкрементируешь.

Что от него хотят (этот концепт std::forward_iterator с C++20):

  • Читать (*it) и писать (*it = value) можно, если он не константный, конечно.
  • Двигаться вперёд (++it, it++) — обязательно.
  • Многопроходность: это не одноразовая сигарета, можно туда-сюда по одному диапазону ходить, пока не надоест.
  • Стабильность ссылок: то, на что он указывает, не испарится просто так, пока ты сам контейнер не изуродуешь.
  • Сравнивать на равенство (==, !=) — чтобы понимать, не упёрся ли уже в конец.

Где такое встречается, ёпта:

  • std::forward_list — односвязный список, туда только вперёд, как в светлое будущее.
  • Все эти unordered_ контейнеры (множества, мапы) — там внутри каша из бакетов, и порядок хрен поймёшь, но пройти вперёд можно.

Пример с std::forward_list, чтобы было совсем ясно:

#include <forward_list>
#include <iostream>

int main() {
    std::forward_list<int> flist = {10, 20, 30, 40};

    // forward_iterator — это как идти по рельсам, назад не получится
    for (auto it = flist.begin(); it != flist.end(); ++it) {
        std::cout << *it << ' '; // Смотрим
        *it += 5;                // Меняем прямо на ходу
    }
    std::cout << 'n';

    // А вот и многопроходность: по тому же самому списку ещё разок
    for (const auto& val : flist) {
        std::cout << val << ' '; // Напечатает: 15 25 35 45
    }
    return 0;
}

Чем он не крут? А тем, что назад шагнуть (--) — ни хуя себе, нельзя. И прыгнуть на 10 элементов вперёд за раз — тоже не выйдет. Это удел более крутых ребят, bidirectional и random access итераторов, которые в std::list и std::vector живут. А этот — просто честный работяга, идёт себе вперёд и не ныть.