Основными итераторами в C ++ являются итератор ввода, итератор вывода, итератор прямого действия, двунаправленный итератор и итератор произвольного доступа. Обратный итератор на самом деле не является итератором; это адаптер итератора. Есть несколько вариантов итераторов, например, постоянный итератор.
Итератор — это разработанный указатель. Как указатель, он указывает на объекты одного типа в памяти в разное время. Все итераторы могут быть разыменованы, за исключением выходного итератора, разыменование которого возможно только для набора типов. Возможность разыменования означает, что значение, на которое указывает указатель или итератор, может быть получено с помощью оператора косвенного обращения *. Таким же образом можно добавить целое число к некоторым итераторам, и с той же целью целое число будет добавлено к указателю.
Вопросы для этой статьи: что это за итераторы? Какие из этих итераторов используются с вектором C ++? Как эти итераторы используются с вектором C ++? Эта статья дает упрощенный ответ на все эти вопросы. В конце статьи, когда будут даны ответы на все эти вопросы, векторные итераторы C ++ станут интуитивно понятными и естественными (для читателя).
Summary Iterators в C ++
Входной итератор
Идея итератора ввода заключается в том, что программа получает входное значение. В отличие от итератора вывода, итератор ввода всегда можно разыменовать. Для двух итераторов ввода, a и b, «a == b» не означает «++ a == ++ b».
Итератор вывода
Идея итератора вывода состоит в том, чтобы программа выдавала выходное значение. В отличие от итератора ввода, итератор вывода не всегда можно разыменовать. Разыменовать его можно только для набора типов.
Прямой итератор
Прямой итератор может сканировать вектор от начала до конца, один за другим (с приращением). У него есть все требования к итератору ввода, а также дополнительные требования. Он может заменить итератор ввода. Для двух итераторов вперед, a и b, «a == b» означает «++ a == ++ b».
Двунаправленный итератор
Двунаправленный итератор может сканировать вектор от начала до конца, один за другим. От конца к началу, по одному (по убыванию). У него есть все требования прямого итератора, а также дополнительные требования. Он может заменить прямой итератор. Для двух двунаправленных итераторов a и b
“a == b” implies “++a == ++b”
and
“–a == –b” implies “a == b”.
Итератор произвольного доступа
Итератор произвольного доступа имеет все требования двунаправленного итератора, а также дополнительные требования. Он может заменить двунаправленный итератор. Итератор произвольного доступа имеет то преимущество, что если он в настоящее время указывает на первый элемент, а четвертый элемент требуется, он пропустит второй и третий элементы и укажет на четвертый элемент. Обратный переход вниз верен.
Обратный итератор
Обратите внимание, что C ++ не имеет обычного обратного итератора, поскольку у него есть прямой итератор. Итак, есть адаптер под названием Reverse Iterator. Есть и другие хорошие новости: обратный итератор отвечает всем требованиям двунаправленного итератора.
Постоянный итератор
Если итератор называется константным итератором, элемент, на который он указывает, изменить нельзя.
Построение векторов и доступ
Контейнеры в C ++: массив классов, двухсторонняя очередь, forward_list, список, вектор, карта, набор, unordered_map и unordered_set. Вектор — это контейнер. Некоторые шаблоны функций в стандартной библиотеке C ++ прямо или косвенно работают с итераторами. Контейнеры C ++, как и вектор, используют эти функции. Эти функции могут быть доступны программе C ++ с помощью любой из следующих директив включения:
#include <iterator>
или
#include <vector>
Включение любого из других контейнеров также сделает доступными эти шаблоны функций. Шаблон функции предназначен для функции, которая может работать с разными типами данных. Вектор использует итераторы через эти шаблоны функций. Вот некоторые из шаблонов функций и их отношения с вектором:
Строительство
Функция шаблона:
template<class C> constexpr auto data(C& c) —> decltype(c.data());
auto означает, что тип возвращаемого значения определяется при вычислении функции. c — объект класса C.
Пример векторного объекта, неявно созданного с помощью this:
vector <char> vtr;
Здесь объект c пуст.
Функция шаблона:
template<class E> constexpr const E* data(initializer_list<E> il) noexcept;
Здесь E * — итератор, указывающий на первый элемент списка или контейнера. Его использование с вектором неявно будет с:
vector <char> vtr{‘A’, ‘B’, ‘C’, ‘D’, ‘E’};
vector<char>::const_iterator it = vtr.begin();
Функция шаблона более применима к оператору begin () (второй оператор).
Доступ
Функция шаблона:
template<class C> constexpr auto size(const C& c) —> decltype(c.size());
Это возвращает размер контейнера. Пример вектора:
vector <char> vtr{‘A’, ‘B’, ‘C’, ‘D’, ‘E’};
int N = vtr.size();
cout << N << endl;
Выход 5.
Функция шаблона:
template<class E> [[nodiscard]] constexpr bool empty(initializer_list<E> il) noexcept;
Возвращает true, если список пуст, или false в противном случае. Пример вектора:
vector <char> vtr{‘A’, ‘B’, ‘C’, ‘D’, ‘E’};
bool bl = vtr.empty();
cout << bl << endl;
На выходе 0 для ложного.
Доступ к диапазону
Существуют и другие функции шаблона, которые используют итераторы, которые вектор использует для решения задач диапазона. Диапазон — это последовательный набор элементов контейнера.
Функция шаблона:
template<class C> constexpr auto begin(C& c) —> decltype(c.begin());
Это возвращает итератор, указывающий на первый элемент в списке. auto здесь означает, что возвращаемое значение определяется при оценке. Пример для вектора:
vector <char> vtr{‘A’, ‘B’, ‘C’, ‘D’, ‘E’};
vector<char>::iterator it = vtr.begin();
cout << *it << ‘\n‘;
Результатом будет A. Итератор, возвращенный здесь, является итератором с произвольным доступом. Можно было вернуть постоянный итератор с произвольным доступом — см. Ниже.
Шаблон функции:
template<class C> constexpr auto end(const C& c) —> decltype(c.end());
Возвращает постоянный итератор, указывающий на последний элемент списка. Векторный код:
vector <char> vtr{‘A’, ‘B’, ‘C’, ‘D’, ‘E’};
vector<char>::const_iterator it = vtr.end();
—it;
cout << *it << ‘ ‘;
—it;
cout << *it << endl;
На выходе будет «ED». Постоянный итератор можно увеличивать или уменьшать, но значение, на которое он указывает, нельзя изменить. Можно было вернуть нормальный итератор с произвольным доступом — см. Ниже.
Шаблон функции:
template<class E> constexpr reverse_iterator<const E*> rbegin(initializer_list<E> il);
Возвращает последнее значение в списке. rbegin () указывает на последний элемент списка, а не дальше последнего элемента списка, как это делает end (). Пример вектора:
vector <char> vtr{‘A’, ‘B’, ‘C’, ‘D’, ‘E’};
vector<char>::reverse_iterator it = vtr.rbegin();
cout << *it << ‘ ‘;
++it;
cout << *it << endl;
Результатом будет: E D. С обратным итератором ++ имеет противоположный эффект для двунаправленного итератора.
Шаблон функции:
template<class E> constexpr reverse_iterator<const E*> rend(initializer_list<E> il);
Указывает непосредственно перед первым элементом списка. Пример вектора:
vector <char> vtr{‘A’, ‘B’, ‘C’, ‘D’, ‘E’};
vector<char>::reverse_iterator it = vtr.rend();
—it;
cout << *it << ‘ ‘;
—it;
cout << *it << endl;
Выход — A B. С обратным итератором — имеет противоположный эффект для ++ двунаправленного итератора.
Под этим заголовком есть и другие функции шаблона — см. Ниже.
Вставить итераторы
reverse_iterator — это адаптер итератора, а не итератор. Итератор вставки также является адаптером итератора. Он удовлетворяет всем требованиям итератора вывода, а также его собственным требованиям. В C ++ он существует в трех формах: back_inserter, front_inserter и вставщик. У каждого из них есть свой конструктор.
back_inserter
Вставки сзади!
Важные прототипы:
explicit back_insert_iterator(Container& x);
back_insert_iterator& operator=(typename Container::value_type&& value);
Пример
вектора : вектор не имеет функции-члена вставки, которая вставляется сзади. Однако функцию-член push_back (t) можно увидеть так.
front_inserter
Вставки спереди!
Важные прототипы:
explicit front_insert_iterator(Container& x);
front_insert_iterator& operator=(typename Container::value_type&& value);
Пример
вектора : вектор не имеет функции-члена вставки, которая вставляется спереди. Вектор также не имеет функции-члена push_front (t).
Хорошая новость заключается в том, что у вектора есть функции-члены вставки, которые можно вставлять где угодно, в начало, внутри или в конец вектора.
inserter
Этот итератор будет вставлять в начало, внутри или в конец вектора.
Важные прототипы:
insert_iterator(Container& x, typename Container::iterator i);
insert_iterator& operator=(typename Container::value_type&& value);
Пример вектора:
vector <char> vtr{‘A’, ‘B’, ‘C’, ‘D’, ‘E’};
vector<char>::iterator it = vtr.begin();
it = it + 2;
vtr.insert(it, ‘c’);for (int i=0; i<vtr.size(); i++)
cout << vtr[i] << «, «;
cout <<endl;
Результат:
A, B, c, C, D, E,
Выражение вставки вектора:
vtr. вставить ( это, ’c’ ) ;
Он вставляет элемент непосредственно перед указателем (им), на который он указывает.
Move Iterator
Move_iterator также является адаптером итератора. Следующая программа похожа на пример из спецификации C ++:
#include <iostream>
#include <list>
#include <vector>
using namespace std;int main()
{
list<char> chs{‘A’, ‘B’, ‘C’, ‘D’, ‘E’};
vector<char> vtr(make_move_iterator(chs.begin()), make_move_iterator(chs.end()));cout << «Original list Content:» << endl;
for (auto it = chs.begin(); it != chs.end(); it++)
cout << *it << «, «;
cout << endl << endl;cout << «Vector Content:» << endl;
for (int i=0; i<vtr.size(); i++)
cout << vtr[i] << «, «;
cout << endl;return 0;
}
Результат:
Исходный список Содержание:
A, B, C, D, E,
Векторный контент:
A, B, C, D, E,
Этот итератор преобразует исходное значение в rvalue перед тем, как поместить его в место назначения.
Заключение
Основными итераторами в C ++ являются итератор ввода, итератор вывода, итератор прямого действия, двунаправленный итератор и итератор произвольного доступа. В стандартной библиотеке C ++ есть несколько шаблонов функций, которые используют эти итераторы. Вектор использует эти итераторы через шаблоны функций. У вектора есть разные имена для некоторых из этих итераторов. Существуют также адаптеры итератора: reverse_iterator, адаптер итератора и move_iterator. Также существуют несколько вариантов итераторов. Достаточно включить в программу все эти функции. После понимания роли этих итераторов, адаптеров и шаблонов функций, которые их используют, использование итераторов с векторами становится интуитивно понятным.