Библиотека итераторов
Итераторы являются обобщением указателей, которые позволяют программе на C++ работать с различными структурами данных (например, с контейнерами и диапазонами(начиная с C++20)) единым образом. Библиотека итераторов предоставляет определения для итераторов, а также свойства итераторов, адаптеры и служебные функции.
Поскольку итераторы являются абстракцией указателей, их семантика является обобщением большей части семантики указателей в C++. Это гарантирует, что каждый шаблон функции, принимающий итераторы, будет работать и с обычными указателями.
Содержание |
[править]Категории итераторов
Существует пять(до C++17)шесть(начиная с C++17) видов итераторов: LegacyInputIterator, LegacyOutputIterator, LegacyForwardIterator, LegacyBidirectionalIterator, LegacyRandomAccessIterator и LegacyContiguousIterator(начиная с C++17). (Смотрите также LegacyIterator , где описан самый базовый тип итератора.)
Вместо того, чтобы определяться конкретными типами, каждая категория итераторов определяется операциями, которые могут быть выполнены с нею. Это определение означает, что любой тип, поддерживающий необходимые операции, может использоваться в качестве итератора – например, указатель поддерживает все операции, требуемые для LegacyRandomAccessIterator, поэтому указатель можно использовать где угодно, где ожидается LegacyRandomAccessIterator.
Все категории итераторов (кроме LegacyOutputIterator) могут быть организованы в иерархию, где более мощные категории итераторов (например, LegacyRandomAccessIterator) поддерживают операции менее мощных категорий (например, LegacyInputIterator). Если итератор попадает в одну из этих категорий и также соответствует требованиям LegacyOutputIterator, то он называется изменяемым итератором и поддерживает ввод и вывод. Неизменяемые итераторы называются константными итераторами.
Итераторы называются constexpr итераторами если все операции, предусмотренные для соответствия требованиям категории итераторов, являются no section name. | (начиная с C++20) |
Категоря итератора | Требования к эксплуатации и хранению | ||||||
---|---|---|---|---|---|---|---|
запись | чтение | инкремент | декремент | произвольный доступ | непрерывное хранилище | ||
без нескольких проходов | с несколькими проходами | ||||||
LegacyIterator | Требует | ||||||
LegacyOutputIterator | Требует | Требует | |||||
LegacyInputIterator (mutable, если поддерживает операцию записи) | Требует | Требует | |||||
LegacyForwardIterator (также соответствует LegacyInputIterator) | Требует | Требует | Требует | ||||
LegacyBidirectionalIterator (также соответствует LegacyForwardIterator) | Требует | Требует | Требует | Требует | |||
LegacyRandomAccessIterator (также соответствует LegacyBidirectionalIterator) | Требует | Требует | Требует | Требует | Требует | ||
LegacyContiguousIterator[1] (также соответствует LegacyRandomAccessIterator) | Требует | Требует | Требует | Требует | Требует | Требует |
- ↑LegacyContiguousIterator была только формально определена в C++17, но итераторы std::vector, std::basic_string, std::array и std::valarray, а также указатели на массивы C часто рассматриваются как отдельная категория в коде до C++17.
Примечание: категория LegacyContiguousIterator была указана в C++17 только формально, но итераторы std::vector, std::basic_string, std::array и std::valarray, а также указатели на массивы C часто рассматриваются как отдельная категория в коде до C++17.
[править]Определения
[править]Типы и записываемость
Итератор ввода i поддерживает выражение *i, приводящее к значению некоторого объектного типаT
, называемого типом значения итератора.
Итератор вывода i имеет непустой набор типов, которые доступны для записи(до C++20)indirectly_writable(начиная с C++20) в итератор; для каждого такого типа | (начиная с C++11) |
Для каждого типа итератора X
для которого определено равенство(до C++20), существует соответствующий знаковый целочисленный(до C++20)целочисленно-подобный(начиная с C++20) тип, называемый разностным типом итератора.
[править]Разыменовываемость и валидность
Точно так же, как обычный указатель на массив гарантирует наличие значения указателя, указывающего на элемент за последним элементом массива, так и для любого типа итератора существует значение итератора, указывающее на элемент за последним элементом соответствующего контейнера(до C++11)последовательности(начиная с C++11). Такое значение называется значением за концом.
Значения итератора i, для которых определено выражение *i называются разыменовываемыми. Стандартная библиотека никогда не предполагает, что значения за конечным значением могут быть разыменованы.
Итераторы также могут иметь единственные значения, не связанные ни с каким контейнером(до C++11)последовательностью(начиная с C++11). Результаты большинства выражений не определены для единственных значений; с единственными исключениями
- присваивание неединственного значения итератору, который содержит единственное значение,
- уничтожение итератора, который содержит единственное значение, и,
| (начиная с C++11) |
В этих случаях единственное значение перезаписывается так же, как и любое другое значение. Разыменовываемые значения всегда не единственные.
Недопустимый итератор это итератор, который может быть единственным.
[править]Диапазоны
Большинство алгоритмических шаблонов стандартной библиотеки, работающих со структурами данных, имеют интерфейсы, использующие диапазоны.
Итератор j называется достижимым из итератора i тогда и только тогда, когда существует конечная последовательность применений выражения ++i, которая делает i == j. Если j достижим из i, они ссылаются на элементы одной и той же последовательности. Диапазон это пара итераторов, обозначающих начало и конец вычисления. Диапазон Диапазон | (до C++20) |
Диапазон это либо
Сравнимый диапазонИтератор и ограничитель, обозначающий диапазон, сравнимы. Ограничитель s называется достижимым из итератора i тогда и только тогда, когда существует конечная последовательность применений выражения ++i, которая делает i == s. Если s достижимо из i, Подсчитываемый диапазонПодсчитываемый диапазонi Подсчитываемый диапазон i
| (начиная с C++20) |
Результат применения функций стандартной библиотеки к недопустимым диапазонам не определён.
[править]Концепты итераторов
В C++20 представлена новая система итераторов, основанная на концептах, которая отличается от итераторов C++17. Хотя основная схема остаётся схожей, требования к отдельным категориям итераторов несколько отличаются.
Определены в пространстве имён std | |
(C++20) | указывает, что тип доступен для чтения косвенно с помощью оператора * (концепт) |
(C++20) | указывает, что значение может быть записано в объект, на который указывает ссылка итератора (концепт) |
(C++20) | указывает, что тип semiregular может увеличиваться с помощью операторов до и после инкремента (концепт) |
(C++20) | указывает, что операция инкремента для типа weakly_incrementable сохраняет равенство и что этот тип является equality_comparable (концепт) |
(C++20) | указывает, что объекты типа могут быть инкрементированы и разыменованы (концепт) |
(C++20) | указывает, что тип является ограничителем для типа input_or_output_iterator (концепт) |
(C++20) | указывает, что оператор - может быть применён к итератору и ограничителю, чтобы вычислить их разницу за постоянное время (концепт) |
(C++20) | указывает, что тип является итератором ввода, то есть значения, на которые он ссылается, могут быть прочитаны, и он может быть как пре-инкрементирован, так и пост-инкрементирован (концепт) |
(C++20) | указывает, что тип является итератором вывода для данного типа значения, то есть в него могут быть записаны значения этого типа, и он может быть как пре-, так и пост-инкрементирован (концепт) |
(C++20) | указывает, что input_iterator является прямым итератором, поддерживающим сравнение на равенство и многопроходность (концепт) |
(C++20) | указывает, что forward_iterator является двунаправленным итератором, поддерживающим движение назад (концепт) |
(C++20) | указывает, что bidirectional_iterator это итератор с произвольным доступом, поддерживающий продвижение за постоянное время и индексирование (концепт) |
(C++20) | указывает, что random_access_iterator является непрерывным итератором, ссылающимся на смежные элементы памяти (концепт) |
[править]Типы, связанные с итераторами
Определены в пространстве имён std | |
(C++20) | вычисляет разностный тип типа weakly_incrementable (шаблон класса) |
(C++20) | вычисляет тип значения типа indirectly_readable (шаблон класса) |
(C++20)(C++20)(C++23)(C++20)(C++20)(C++20) | вычисляет связанные типы итератора (псевдоним шаблона) |
[править]Примитивы итераторов
предоставляет единый интерфейс к свойствам итератора (шаблон класса) | |
пустые типы классов, используемые для обозначения категорий итераторов (класс) | |
(устарело в C++17) | базовый класс для упрощения определения требуемых типов для простых итераторов (шаблон класса) |
[править]Точки настройки итераторов
Определены в пространстве имён std::ranges | |
(C++20) | приводит результат разыменования объекта к связанному с ним типу правосторонней ссылки (объект точки настройки) |
(C++20) | меняет местами значения, на которые ссылаются два разыменовываемых объекта (объект точки настройки) |
[править]Концепты алгоритмов и утилиты
C++20 также предоставляет набор концептов и связанных шаблонов служебных утилит, предназначенных для упрощения ограничения операций общих алгоритмов.
Определены в заголовочном файле <iterator> | |
Определены в пространстве имён std | |
Косвенно вызываемые концепты | |
указывает, что вызываемый тип может быть вызван в результате разыменования типа indirectly_readable (концепт) | |
(C++20) | указывает, что вызываемый тип, когда он вызывается с результатом разыменования типа indirectly_readable , соответствует predicate (концепт) |
(C++20) | указывает, что вызываемый тип, когда он вызывается с результатом разыменования двух типов indirectly_readable , соответствует predicate (концепт) |
указывает, что вызываемый тип при вызове в результате разыменования двух типов indirectly_readable , соответствует equivalence_relation (концепт) | |
(C++20) | указывает, что вызываемый тип, когда он вызывается с результатом разыменования двух типов indirectly_readable , соответствует strict_weak_order (концепт) |
Общие требования к алгоритмам | |
(C++20) | указывает, что значения могут быть перемещены из типа indirectly_readable в тип indirectly_writable (концепт) |
(C++20) | указывает, что значения могут быть перемещены из типа indirectly_readable в тип indirectly_writable и что перемещение может быть выполнено через промежуточный объект (концепт) |
(C++20) | указывает, что значения могут быть скопированы из типа indirectly_readable в тип indirectly_writable (концепт) |
(C++20) | указывает, что значения могут быть скопированы из типа indirectly_readable в тип indirectly_writable что копирование может быть выполнено через промежуточный объект (концепт) |
(C++20) | указывает, что значения, на которые ссылаются два типа indirectly_readable , можно поменять местами (концепт) |
(C++20) | указывает, что значения, на которые ссылаются два типа indirectly_readable , могут сравниваться (концепт) |
(C++20) | определяет общие требования к алгоритмам, которые меняют порядок элементов на месте (концепт) |
(C++20) | определяет требования к алгоритмам, которые объединяют отсортированные последовательности в выходную последовательность путём копирования элементов (концепт) |
(C++20) | определяет общие требования алгоритмов, которые переставляют последовательности в упорядоченные последовательности (концепт) |
Утилиты | |
(C++20) | вычисляет результат вызова вызываемого объекта на результате разыменования некоторого набора типов indirectly_readable (псевдоним шаблона) |
(C++20) | вспомогательный шаблон для определения ограничений для алгоритмов, принимающих прогнозы (шаблон класса) |
[править]Адаптеры итераторов
адаптер итератора для обхода в обратном порядке (шаблон класса) | |
(C++14) | создаёт std::reverse_iterator типа, выведенного из аргумента (шаблон функции) |
адаптер итератора для вставки в конец контейнера (шаблон класса) | |
создаёт std::back_insert_iterator типа, выведенного из аргумента (шаблон функции) | |
адаптер итератора для вставки в начало контейнера (шаблон класса) | |
создаёт std::front_insert_iterator типа, выведенного из аргумента (шаблон функции) | |
адаптер итератора для вставки в контейнер (шаблон класса) | |
создаёт std::insert_iterator типа, выведенного из аргумента (шаблон функции) | |
(C++23) | адаптер итератора, который преобразует итератор в константный итератор (шаблон класса) |
(C++23) | вычисляет константный тип итератора для заданного типа (псевдоним шаблона) |
(C++23) | вычисляет тип ограничителя, который будет использоваться с константными итераторами (псевдоним шаблона) |
(C++23) | создаёт std::const_iterator типа, полученного из аргумента (шаблон функции) |
(C++23) | создаёт std::const_sentinel типа, выведенного из аргумента (шаблон функции) |
(C++11) | адаптер итератора, который разыменовывается в правостороннюю ссылку (шаблон класса) |
(C++20) | адаптер ограничитель для использования с std::move_iterator (шаблон класса) |
(C++11) | создаёт std::move_iterator типа, выведенного из аргумента (шаблон функции) |
(C++20) | адаптирует тип итератора и его ограничителя к общему типу итератора (шаблон класса) |
(C++20) | ограничитель по умолчанию для использования с итераторами, которые знают границу своего диапазона (класс) |
(C++20) | адаптер итератора, отслеживающий расстояние до конца диапазона (шаблон класса) |
(C++20) | ограничитель, который всегда сравнивает на неравенство с любым типом weakly_incrementable (класс) |
[править]Потоковые итераторы
итератор ввода, читающий из std::basic_istream (шаблон класса) | |
итератор вывода, записывающий в std::basic_ostream (шаблон класса) | |
итератор ввода, читающий из std::basic_streambuf (шаблон класса) | |
итератор вывода, записывающий в std::basic_streambuf (шаблон класса) |
[править]Операции над итераторами
Определены в заголовочном файле <iterator> | |
продвигает итератор на заданное расстояние (функция) | |
возвращает расстояние между двумя итераторами (функция) | |
(C++11) | инкрементирует итератор (функция) |
(C++11) | декрементирует итератор (функция) |
(C++20) | продвигает итератор на заданное расстояние или до заданной границы (ниблоид) |
(C++20) | возвращает расстояние между итератором и ограничителем или между началом и концом диапазона (ниблоид) |
(C++20) | инкрементирует итератор на заданное расстояние или до границы (ниблоид) |
(C++20) | декрементирует итератор на заданное расстояние или до границы (ниблоид) |
[править]Доступ к диапазону
Эти функции, не являющиеся элементами, предоставляют общий интерфейс для контейнеров, простых массивов и std::initializer_list.
Определены в заголовочном файле <array> | |
Определены в заголовочном файле <deque> | |
Определены в заголовочном файле <forward_list> | |
Определены в заголовочном файле <iterator> | |
Определены в заголовочном файле <list> | |
Определены в заголовочном файле <map> | |
Определены в заголовочном файле <regex> | |
Определены в заголовочном файле <set> | |
Определены в заголовочном файле <span> | |
Определены в заголовочном файле <string> | |
Определены в заголовочном файле <string_view> | |
Определены в заголовочном файле <unordered_map> | |
Определены в заголовочном файле <unordered_set> | |
Определены в заголовочном файле <vector> | |
Определены в пространстве имён std | |
(C++11)(C++14) | возвращает итератор на начало контейнера или массива (шаблон функции) |
(C++11)(C++14) | возвращает итератор на конец контейнера или массива (шаблон функции) |
(C++14) | возвращает обратный итератор на начало контейнера или массива (шаблон функции) |
(C++14) | возвращает обратный конечный итератор для контейнера или массива (шаблон функции) |
(C++17)(C++20) | возвращает размер контейнера или массива (шаблон функции) |
(C++17) | проверяет, пустой ли контейнер (шаблон функции) |
(C++17) | получает указатель на базовый массив (шаблон функции) |
[править]Отчёты о дефектах
Следующие изменения поведения были применены с обратной силой к ранее опубликованным стандартам C++:
Номер | Применён | Поведение в стандарте | Корректное поведение |
---|---|---|---|
CWG 1181 | C++98 | типы массивов не могут быть типами значений | могут |
LWG 208 | C++98 | итераторы за концом всегда были неособыми | они могут быть особыми |
LWG 278 | C++98 | допустимость итератора не была определена | определяется как всегда неособый |
LWG 324 | C++98 | выходные итераторы имели типы значений | вместо этого выходные итераторы имеют перезаписываемые типы |
LWG 407 | C++98 | особые итераторы не могли быть уничтожены | позволено |
LWG 408 | C++98 | особые итераторы не могли быть скопированы | разрешено, если они инициализированы значением |
LWG 1185 | C++98 | LegacyForwardIterator, LegacyBidirectionalIterator и LegacyRandomAccessIterator всегда соответствуют LegacyOutputIterator | они могут не соответствовать LegacyOutputIterator |
LWG 1210 | C++98 | определение сингулярности и достижимости итератора зависело от контейнеров | вместо этого зависит от последовательностей |