Итераторы
Итератор — это объект, который может перебирать элементы в контейнере стандартной библиотеки С++ и предоставлять доступ к отдельным элементам. Все контейнеры стандартной библиотеки С++ предоставляют итераторы, чтобы алгоритмы могли получить доступ к их элементам стандартным способом, независимо от типа контейнера, в котором сохранены элементы.
Итераторы можно использовать явным образом с помощью функций-членов и глобальных функций, таких как и 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++