Поделиться через


Итераторы

Итератор — это объект, который может перебирать элементы в контейнере стандартной библиотеки С++ и предоставлять доступ к отдельным элементам. Все контейнеры стандартной библиотеки С++ предоставляют итераторы, чтобы алгоритмы могли получить доступ к их элементам стандартным способом, независимо от типа контейнера, в котором сохранены элементы.

Итераторы можно использовать явным образом с помощью функций-членов и глобальных функций, таких как и end() операторы, такие как -- begin() ++ и перемещение вперед или назад. Кроме того, можно использовать итераторы неявно с диапазоном для цикла или (для некоторых типов итератора) подстрочного оператора [].

В стандартной библиотеке С++ началом последовательности или диапазона является первый элемент. Конец последовательности или диапазона всегда определяется как элемент, следующий за последним элементом. Глобальные функции begin и возвращают итераторы end в указанный контейнер. Типичный цикл явных итераторов, включающий все элементы, выглядит следующим образом:

vector<int> vec{ 0,1,2,3,4 };
for (auto it = begin(vec); it != end(vec); it++)
{
    // Access element using dereference operator
    cout << *it << " ";
}

Того же можно достичь более простым способом, с помощью цикла range-for:

for (auto num : vec)
{
    // no dereference operator
    cout << num << " ";
}

Существует пять категорий итераторов. Ниже описаны категории в порядке возрастания силы.

  • Выход. Выходной итератор X может выполнять итерацию по последовательности с помощью ++ оператора и может записывать элемент только один раз с помощью * оператора.

  • Ввод. Входной итератор X может выполнять итерацию по последовательности с помощью ++ оператора и читать элемент в любое количество раз с помощью * оператора. Вы можете сравнить входные итераторы с помощью == операторов и != операторов. После увеличения любой копии входного итератора ни одна из других копий не может быть безопасно сравниваема, разыменовывается или увеличивается после этого.

  • Переслать. Переадресация итератора X может выполнять итерацию по последовательности с помощью оператора ++ и может считывать любой элемент или записывать элементы, отличные от const, с помощью * оператора. Вы можете получить доступ к элементам элемента с помощью -> оператора и сравнения переадресации итераторов с помощью == операторов и != операторов. Вы можете сделать несколько копий однонаправленного итератора, каждая из которых может быть разыменована и для нее может быть выполнено независимое приращение. Итератор пересылки, который инициализирован без ссылки на любой контейнер, называется итератором пересылки null. Пустые однонаправленные итераторы всегда равны.

  • Двунаправленный. Двунаправленный итератор может занять место итератора X вперед. Однако можно также уменьшать двунаправленный итератор, как и в --X, X--или (V = *X--). Получить доступ к членам элементов и сравнить двунаправленные итераторы можно так же, как и однонаправленные итераторы.

  • Произвольный доступ. Итератор случайного доступа может занять место двунаправленного итератораX. С помощью итератора случайного доступа можно использовать оператор [] подстрока для доступа к элементам. Вы можете использовать +-+= операторы и -= операторы для перемещения вперед или назад указанного количества элементов и вычисления расстояния между итераторами. Вы можете сравнить двунаправленные итераторы с помощью ==, , , <, >и <=>=. !=

Все итераторы можно назначать и копировать. Предполагается, что они являются упрощенными объектами и часто передаются и возвращаются по значению, а не по ссылке. Обратите внимание, что ни одна из операций, описанных выше, не может создавать исключения при выполнении с допустимым итератором.

Иерархия категорий итераторов может быть представлена в виде трех последовательностей. Для доступа в режиме только для записи в последовательность можно использовать любой из следующих итераторов.

итератор вывода
—> переадресация итератора
—> двунаправленный итератор
—> итератор случайного доступа

Стрелка вправо означает", что "можно заменить". Любой алгоритм, вызывающий итератор выходных данных, должен хорошо работать с итератором пересылки, например, но не другим способом.

Для доступа в режиме только для чтения в последовательность можно использовать любой из следующих итераторов.

итератор ввода
—> переадресация итератора
—> двунаправленный итератор
—> итератор случайного доступа

Итератор ввода является самым слабым по всем категориям в этом смысле.

Наконец, для доступа в режиме чтения и записи в последовательность можно использовать любой из следующих итераторов.

итератор пересылки
—> двунаправленный итератор
—> итератор случайного доступа

Указатель на объект всегда можно использовать как итератор произвольного доступа, поэтому он может относиться к любой категории итераторов, если он поддерживает необходимый уровень доступа для чтения и записи в последовательность, которую он обозначает.

Итератор Iterator, не являющийся указателем на объект, должен также определять типы элементов, необходимые для специализации iterator_traits<Iterator>. Эти требования можно выполнить, исходя Iterator из итератора общедоступного базового класса.

Важно понимать обещания и ограничения каждой категории итератора, чтобы узнать, как итераторы используются контейнерами и алгоритмами в стандартной библиотеке C++.

Примечание.

Вы можете избежать явного использования итераторов с помощью циклов range-for. Дополнительные сведения см. в разделе "Диапазон" для инструкции.

Microsoft C++ теперь предлагает проверенные итераторы и отладочные итераторы, чтобы убедиться, что границы контейнера не перезаписываются. Дополнительные сведения см. в разделах Проверяемые итераторы и Поддержка отладочных итераторов.

См. также

Справочник по стандартной библиотеке C++
Потокобезопасность в стандартной библиотеке C++