Урок №198. Итераторы STL

  Юрий  | 

    | 

  Обновл. 10 Янв 2019  | 

 1215

 ǀ   2 

В предыдущем уроке мы рассматривали контейнеры STL, а сейчас будем рассматривать итераторы STL.

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

Функционал итераторов

Об итераторе можно думать, как об указателе на определенный элемент контейнерного класса с дополнительным набором перегруженных операторов для выполнения чётко определённых функций:

   Оператор * возвращает элемент, на который в данный момент указывает итератор.

   Оператор ++ перемещает итератор к следующему элементу контейнера. Большинство итераторов также предоставляют оператор −− для перехода к предыдущему элементу.

   Операторы == и != используются для определения того, указывают ли два итератора на один и тот же элемент или нет. Для сравнения значений, на которые указывают два итератора, нужно сначала разыменовать эти итераторы, а затем использовать оператор == или !=.

   Оператор = присваивает итератору новую позицию (обычно начало или конец элементов контейнера). Чтобы присвоить значение элемента, на который указывает итератор, другому объекту, нужно сначала разыменовать итератор, а затем использовать оператор =.

Каждый контейнерный класс имеет 4 основных метода для работы с оператором =:

   begin() возвращает итератор, представляющий начало элементов контейнера.

   end() возвращает итератор, представляющий элемент, который находится после последнего элемента в контейнере.

   cbegin() возвращает константный (только для чтения) итератор, представляющий начало элементов контейнера.

   cend() возвращает константный (только для чтения) итератор, представляющий элемент, который находится после последнего элемента в контейнере.

Может показаться странным, что end() не указывает на последний элемент контейнера, но это сделано в целях упрощения использования циклов: цикл перебирает элементы до тех пор, пока итератор не достигнет end(), и тогда уже всё – «Баста!».

Наконец, все контейнеры предоставляют (как минимум) два типа итераторов:

   container::iterator — итератор для чтения/записи;

   container::const_iterator — итератор только для чтения.

Рассмотрим несколько примеров использования итераторов.

Итерация по вектору


Заполним вектор 5-тью числами и, с помощью итераторов, выведем значения вектора:

Результат выполнения программы выше:

0 1 2 3 4

Итерация по списку

Выполним всё то же, что выше, только уже со списком:

Результат выполнения программы выше:

0 1 2 3 4

Обратите внимание, код этой программы почти идентичен коду выше, хотя реализация векторов и списков значительно отличается друг от друга!

Итерация по set-у


В следующей программе мы создадим set из 5 чисел и, используя итератор, выведем эти значения:

Результат выполнения программы выше:

-4 2 3 8 9

Обратите внимание, хотя заполнение set-a элементами отличается от способа заполнения вектора и списка выше, но код, используемый для перебора элементов set-a — идентичен.

Итерация по ассоциативному массиву

Этот пример немного сложнее. Контейнеры map и multimap принимают пары элементов (определённых как std::pair). Мы используем вспомогательную функцию make_pair() для создания пар. std::pair позволяет получить доступ к элементу (паре ключ-значение) через первый и второй члены. В нашем ассоциативном массиве мы используем первый член в качестве ключа, а второй – в качестве значения:

Результат выполнения программы выше:

1=spider 2=dog 3=cat 4=lion 5=chicken

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

Заключение


Итераторы предоставляют простой способ перебора элементов контейнерного класса без необходимости знать реализацию определённого контейнерного класса. В сочетании с алгоритмами STL и методами контейнерных классов итераторы становятся ещё более мощными. В следующем уроке мы рассмотрим пример использования итераторов для вставки элементов в list (у которого нет перегруженного оператора индексации [] для прямого доступа к элементам).

Стоит отметить ещё один момент: Итераторы должны быть реализованы для каждого контейнера отдельно, поскольку итератор должен знать реализацию контейнерного класса. Таким образом, итераторы всегда привязаны к конкретным контейнерным классам.

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (11 оценок, среднее: 5,00 из 5)
Загрузка...

Комментариев: 2

  1. Аватар dshadov:

    Здравствуйте!

    А для чего при вставке элементов в map использовать пары, если и без них все прекрасно вставляется, например так:

    или даже так:

    Это равнозначный синтаксис или есть какое-то преимущество вставки через пары?

    1. Аватар Артем:

      Это равнозначный синтаксис

Добавить комментарий

Ваш E-mail не будет опубликован. Обязательные поля помечены *