Random access iterator c что это
Интересная логика Random access итераторов в STL контейнерах
Коротко об итераторах
Создаём итератор
Итак, создадим два вектора целых чисел:
Заполним оба числами от 0 до 14:
Создадим итераторы для каждого вектора:
Собственно интересные особенности
Первое что бросилось мне в глаза — этот наличие перегруженного оператора «-» и отсутствие перегруженного оператора «+» для двух итераторов (сложение итератора с интом предусмотрено). Создадим дополнительный итератор для первого вектора и проделаем оба действия:
В первом случае получаем на выходе 3, во втором — ошибку компиляции.
Во-вторых, меня заинтересовал вопрос равенства итераторов. Исходя из определения, итератор должен обеспечивать доступ к элементам коллекции. Т. е. если два итератора принадлежат разным коллекциям, кэп подсказывает, что сравнивать их вообще нельзя. Однако:
На выходе имеем «Not equal», что при странности самой возможности такого сравнения, весьма логично.
После того, как я понял, что сравнивать итераторы разных объектов можно, решил попробовать вычесть один из другого:
На выходе получаем 34. Сразу вспомнился Пелевин и его «Числа».
То, что на выходе мы получаем непредсказуемый инт связано с тем, как располагаются векторы в памяти относительно друг друга. Попробовав позаполнять оба вектора разным количеством чисел, получал совершенно разный результат.
Ну и самое интересное:
На выходе, как Вы уже догадались «Equal». Это ведёт к следующему, неутешительному с моей точки зрения выводу, что:
позволит нам итерировать первый вектор, а не второй.
Язык C++
Итераторы
При обсуждении алгоритмов стандартной библиотеки C++ мы постоянно использовали итераторы. Из контекста мы поняли, что итераторы используются для указывания на элементы контейнеров. Пришло время сформировать более полное представление об этих объектах, узнать какие типы итераторов существуют, рассмотреть еще несколько ситуаций, в которых полезно использование итераторов.
Определение и классификация итераторов
Итератор — это объект, который указывает на элемент в диапазоне элементов (например, в массиве), с помощью итератора можно перебирать элементы диапазона, используя определенный набор операций. Для итератора определены по крайней мере операторы инкремента ( ++ ) и разыменовывания ( * ).
Существует пять типов итераторов, организованных следующим образом:
Output итераторы можно разыменовывать в левой части выражений:
Если открыть документацию алгоритмов, которые мы рассматривали раньше, то можно уточнить наше понимание работы алгоритмов с итераторами: каждый алгоритм предъявляет требования к итератору, с которым его можно использовать. Например, один из вариантов алгоритма find определен так:
т.е. для работы с этим алгоритмом итератор должен всего лишь обладать возможностями Input Iterator. А вот как выглядит один из вариантов алгоритма sort :
Сортировка за «линеарифмическое» время требует доступа к элементам диапазона по индексу, поэтому алгоритм sort требует Random access Iterator.
Теперь, когда мы разобрались с основными понятиями, рассмотрим несколько ситуаций, в которых полезно использовать итераторы.
Итераторы и цикл for
А что, если у нас есть два контейнера set одинакового размера, и мы хотим синхронно пройти по ним в цикле. В подобных ситуациях на помощь приходят итераторы:
Наконец, если мы работаем с константным объектом, либо если мы хотим избежать случайной модификации элементом диапазона, то следует использовать константный итератор const_iterator и методы cbegin() и cend() :
Конструирование контейнеров с помощью итераторов
Практически все стандартные контейнеры могут быть сконструированы с помощью двух итераторов, указывающих на границы диапазона элементов. Это позволяет, например, одной строчкой создавать и наполнять новый контейнер элементами другого контейнера, даже если типы контейнеров отличаются:
Вставка объектов с помощью back_inserter
Резюме
std:: random_access_iterator
Compiler support | ||||
Freestanding and hosted | ||||
Language | ||||
Standard library headers | ||||
Named requirements | ||||
Feature test macros (C++20) | ||||
Language support library | ||||
Concepts library (C++20) | ||||
Diagnostics library | ||||
General utilities library | ||||
Strings library | ||||
Containers library | ||||
Iterators library | ||||
Ranges library (C++20) | ||||
Algorithms library | ||||
Numerics library | ||||
Localizations library | ||||
Input/output library | ||||
Filesystem library (C++17) | ||||
Regular expressions library (C++11) | ||||
Atomic operations library (C++11) | ||||
Thread support library (C++11) | ||||
Technical specifications | ||||
Symbols index | ||||
External libraries |
Contents
[edit] Iterator concept determination
[edit] Semantic requirements
[edit] Equality preservation
An expression is equality preserving if it results in equal outputs given equal inputs.
In specification of standard concepts, operands are defined as the largest subexpressions that include only:
The cv-qualification and value category of each operand is determined by assuming that each template type parameter denotes a cv-unqualified complete non-array object type.
Every expression required to be equality preserving is further required to be stable: two evaluations of such an expression with the same input objects must have equal outputs absent any explicit intervening modification of those input objects.
Unless noted otherwise, every expression used in a requires-expression is required to be equality preserving and stable, and the evaluation of the expression may only modify its non-constant operands. Operands that are constant must not be modified.
[edit] Implicit expression variations
A requires-expression that uses an expression that is non-modifying for some constant lvalue operand also implicitly requires additional variations of that expression that accept a non-constant lvalue or (possibly constant) rvalue for the given operand unless such an expression variation is explicitly required with differing semantics. These implicit expression variations must meet the same semantic requirements of the declared expression. The extent to which an implementation validates the syntax of the variations is unspecified.
[edit] Notes
Unlike the LegacyRandomAccessIterator requirements, the random_access_iterator concept does not require dereference to return an lvalue.
[edit] Example
Demonstrates a possible implementation of std::distance via C++20 concepts.
Итераторы произвольного доступа (Random access iterators)
Итераторы произвольного доступа (Random access iterators)
Класс или встроенный тип X удовлетворяет требованиям итераторов произвольного доступа, если к таблице, которая определяет двунаправленные итераторы, мы добавим следующие строки:
Таблица 6: Требования итератора произвольного доступа (в дополнение к двунаправленному итератору)
Читайте также
12.6.2. Функции POSIX: random() и srandom()
12.6.2. Функции POSIX: random() и srandom() BSD 4.3 ввело random() и сопровождающие ее функции. Эти функции используют намного более подходящий генератор случайных чисел, который возвращает 31-разрядное значение. Теперь они входят в расширение XSI, стандартизованное POSIX:#include /* XSI */long
Итераторы ввода (Input iterators)
Итераторы ввода (Input iterators) Класс или встроенный тип X удовлетворяет требованиям итератора ввода для значимого типа T, если справедливы следующие выражения:Таблица 2. Требования итератора ввода выражение возвращаемый тип семантика исполнения утверждение/примечание
Итераторы вывода (Output iterators)
Итераторы вывода (Output iterators) Класс или встроенный тип X удовлетворяет требованиям итератора вывода, если справедливы следующие выражения:Таблица 3. Требования итератора вывода выражение возвращаемый тип семантика исполнения утверждение/примечание состояние до/после
Последовательные итераторы (Forward iterators)
Последовательные итераторы (Forward iterators) Класс или встроенный тип X удовлетворяет требованиям последовательного итератора, если справедливы следующие выражения:Таблица 4. Требования последовательного итератора выражение возвращаемый тип семантика исполнения
Двунаправленные итераторы (Bidirectional iterators)
Двунаправленные итераторы (Bidirectional iterators) Класс или встроенный тип X удовлетворяет требованиям двунаправленного итератора, если к таблице, которая определяет последовательные итераторы, мы добавим следующие строки:Таблица 5. Требования двунаправленного итератора (в
Перетасовать (Random shuffle)
Перетасовать (Random shuffle) template ‹class RandomAccessIterator›void random_shuffle(RandomAccessIterator first, RandomAccessIterator last);template ‹class RandomAccessIterator, class RandomNumberGenerator›void random_shuffie(RandomAccessIterator first, RandomAccessIterator last, RandomNumberGenerator& rand);random_shuffle переставляет элементы в диапазоне [first, last) с равномерным распределением.
Обратные итераторы (Reverse iterators)
Обратные итераторы (Reverse iterators) Двунаправленные итераторы и итераторы произвольного доступа имеют соответствующие адаптеры обратных итераторов, которые выполняют итерации через структуру данных в противоположном направлении.Они имеют те же самые сигнатуры, как и
Итераторы вставки (Insert iterators)
Итераторы вставки (Insert iterators) Чтобы было возможно иметь дело с вставкой таким же образом, как с записью в массив, в библиотеке обеспечивается специальный вид адаптеров итераторов, называемых итераторами вставки (insert iterators). С обычными классами итераторовwhile (first!= last) *result++ =
8.2. Функция access(): проверка прав доступа к файлу
8.2. Функция access(): проверка прав доступа к файлу Функция access() определяет, имеет ли вызывающий ее процесс право доступа к заданному файлу. Функция способна проверить любую комбинацию привилегий чтения, записи и выполнения, а также факт существования файла.Функция access()
Отыскание произвольного элемента в сортирующем дереве
Выполнение произвольного кода
Выполнение произвольного кода Для плохо защищенных систем все текущие версии Firebird предоставляют возможность выполнения произвольного кода с помощью внешних функций, фильтров BLOB и реализаций пользовательских наборов символов. Такие внешние модули выполняются в том же
Random’s Flash&Backup
Random’s Flash&Backup В качестве примера рассмотрим программу Random’s Flash&Backup. Эта сервисная программа для телефонов Motorola семейства P2K, созданная независимым разработчиком, демонстрирует все типичные основные возможности программ такого рода:• создание/восстановление
Руководство по стандартной библиотеке шаблонов (STL)
Произвольного доступа | Двунаправленные | Последовательные |
|
Все категории итераторов требуют только те функции, которые осуществимы для данной категории со сложностью постоянного времени (амортизированные). Поэтому таблицы требований для итераторов не имеют столбца сложности.
Итераторы ввода (Input iterators)
Итераторы вывода (Output iterators)
Класс или встроенный тип X удовлетворяет требованиям итератора вывода, если справедливы следующие выражения:
Последовательные итераторы (Forward iterators)
Класс или встроенный тип X удовлетворяет требованиям последовательного итератора, если справедливы следующие выражения:
ПРИМЕЧАНИЕ. Тот факт, что r == s подразумевает ++r == ++s (что неверно для итераторов ввода и вывода) и что удалено ограничение на число присваиваний через итератор (которое применяется к итераторам вывода), позволяет использование многопроходных однонаправленных алгоритмов с последовательными итераторами.
Двунаправленные итераторы (Bidirectional iterators)
Класс или встроенный тип X удовлетворяет требованиям двунаправленного итератора, если к таблице, которая определяет последовательные итераторы, мы добавим следующие строки:
ПРИМЕЧАНИЕ. Двунаправленные итераторы позволяют алгоритмам перемещать итераторы назад также, как вперёд.
Итераторы произвольного доступа (Random access iterators)
Класс или встроенный тип X удовлетворяет требованиям итераторов произвольного доступа, если к таблице, которая определяет двунаправленные итераторы, мы добавим следующие строки:
Теги итераторов (Iterator tags)
Примеры использования тегов итераторов
Для всех типов обычных указателей мы можем определить value_type и distance_type с помощью следующего:
Определяемый пользователем итератор BinaryTreeIterator может быть включен в категорию двунаправленных итераторов следующим образом:
Если шаблонная функция evolve хорошо определена для двунаправленных итераторов, но может быть осуществлена более эффективно для итераторов произвольного доступа, тогда реализация выглядит так: