Что такое random_access_iterator в C++ STL?

«Что такое random_access_iterator в C++ STL?» — вопрос из категории STL, который задают на 25% собеседований C/C++ Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Random Access Iterator (итератор произвольного доступа) — это наиболее мощная категория итераторов в C++ STL. Он моделирует поведение указателя на элементы массива, предоставляя возможность перемещаться по контейнеру не только последовательно, но и с произвольными "прыжками" (арифметика указателей), а также сравнивать позиции итераторов.

Иерархия категорий итераторов (от наиболее ограниченных к наиболее мощным):

  1. Input / Output Iterator (ввод/вывод) — только последовательное чтение/запись вперёд.
  2. Forward Iterator (однонаправленный) — движение только вперёд, но допускает многократные проходы.
  3. Bidirectional Iterator (двунаправленный) — добавляет возможность движения назад (--).
  4. Random Access Iterator (произвольного доступа) — включает все возможности предыдущих и добавляет арифметику.

Операции, поддерживаемые Random Access Iterator (помимо операций Bidirectional Iterator):

  • Арифметика с целыми числами: it + n, it - n, n + it, it += n, it -= n
  • Вычисление расстояния: it1 - it2 (возвращает разность типа difference_type)
  • Оператор индексации (доступ по смещению): it[n] (эквивалентно *(it + n))
  • Сравнение порядка: it1 < it2, it1 > it2, it1 <= it2, it1 >= it2

Контейнеры, предоставляющие Random Access Iterators:

  • std::vector
  • std::array
  • std::deque
  • Обычные указатели (например, int*) также являются random access итераторами.

Контейнеры, которые НЕ предоставляют Random Access Iterators:

  • std::list, std::forward_list (предоставляют Bidirectional и Forward соответственно)
  • std::set, std::map, std::multiset, std::multimap (Bidirectional)
  • std::unordered_* (Forward)

Пример, демонстрирующий возможности:

#include <iostream>
#include <vector>
#include <algorithm> // для std::sort

int main() {
    std::vector<int> data = {9, 1, 5, 3, 7, 2, 8, 4, 6};

    // 1. Получаем random access итераторы
    auto begin_it = data.begin();
    auto end_it = data.end();

    // 2. Арифметика указателей: быстрый доступ к середине контейнера
    auto mid_it = begin_it + (end_it - begin_it) / 2;
    std::cout << "Middle element: " << *mid_it << 'n'; // 7

    // 3. Оператор индексации (работает как с массивом)
    std::cout << "Element at index 3: " << begin_it[3] << 'n'; // 3

    // 4. Сравнение порядка итераторов
    if (begin_it + 2 < mid_it) {
        std::cout << "Third element is before the middle.n";
    }

    // 5. Алгоритмы, требующие Random Access Iterator (например, быстрая сортировка)
    // std::sort не может работать с std::list, но отлично работает с std::vector.
    std::sort(begin_it, end_it);

    std::cout << "Sorted data: ";
    for (auto it = begin_it; it != end_it; ++it) {
        std::cout << *it << ' '; // 1 2 3 4 5 6 7 8 9
    }
    std::cout << 'n';

    // 6. Бинарный поиск (также требует Random Access или хотя бы Forward, но эффективен с Random Access)
    if (std::binary_search(begin_it, end_it, 5)) {
        std::cout << "Found 5 in the sorted vector.n";
    }

    return 0;
}

Практическое значение: Наличие random access итераторов позволяет использовать наиболее эффективные алгоритмы (как std::sort или std::nth_element), которые требуют возможности быстрого произвольного доступа к элементам последовательности.