Вывод вектора с помощью итераторов

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

Обновл. 15 Сен 2021 |

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

Видео:Итераторы STL | Библиотека стандартных шаблонов (stl) | Уроки | C++ | #2Скачать

Итераторы STL | Библиотека стандартных шаблонов (stl) | Уроки | C++ | #2

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Видео:4. Категории итераторов в С++ . Создание собственного итератора.Скачать

4. Категории итераторов в С++ . Создание собственного итератора.

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

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

Видео:vector | Библиотека стандартных шаблонов (stl) | Уроки | C++ | #1Скачать

vector | Библиотека стандартных шаблонов (stl) | Уроки | C++ | #1

Векторные итераторы C++

Основными итераторами в C ++ являются итератор ввода, итератор вывода, итератор прямого действия, двунаправленный итератор и итератор произвольного доступа. Обратный итератор на самом деле не является итератором; это адаптер итератора. Есть несколько вариантов итераторов, например, постоянный итератор.

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

Вопросы для этой статьи: что это за итераторы? Какие из этих итераторов используются с вектором C ++? Как эти итераторы используются с вектором C ++? Эта статья дает упрощенный ответ на все эти вопросы. В конце статьи, когда будут даны ответы на все эти вопросы, векторные итераторы C ++ станут интуитивно понятными и естественными (для читателя).

Видео:19. Виды итераторов. Внутреннее устройство vectorСкачать

19. Виды итераторов. Внутреннее устройство vector

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++] Создаем итератор самостоятельноСкачать

[C++] Создаем итератор самостоятельно

Итератор произвольного доступа

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

Видео:1 Введение в итераторыСкачать

1 Введение в итераторы

Обратный итератор

Обратите внимание, что C ++ не имеет обычного обратного итератора, поскольку у него есть прямой итератор. Итак, есть адаптер под названием Reverse Iterator. Есть и другие хорошие новости: обратный итератор отвечает всем требованиям двунаправленного итератора.

Видео:Доступ к элементам vector с помощью итераторов | Занятие 17 (ч.5) | Изучаем С++ вместеСкачать

Доступ к элементам vector с помощью итераторов | Занятие 17 (ч.5) | Изучаем С++ вместе

Постоянный итератор

Если итератор называется константным итератором, элемент, на который он указывает, изменить нельзя.

Построение векторов и доступ

Контейнеры в C ++: массив классов, двухсторонняя очередь, forward_list, список, вектор, карта, набор, unordered_map и unordered_set. Вектор — это контейнер. Некоторые шаблоны функций в стандартной библиотеке C ++ прямо или косвенно работают с итераторами. Контейнеры C ++, как и вектор, используют эти функции. Эти функции могут быть доступны программе C ++ с помощью любой из следующих директив включения:

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

Видео:[C++] STL: ИтераторыСкачать

[C++] STL: Итераторы

Строительство

auto означает, что тип возвращаемого значения определяется при вычислении функции. c — объект класса C.

Пример векторного объекта, неявно созданного с помощью this:

Здесь объект c пуст.

Здесь E * — итератор, указывающий на первый элемент списка или контейнера. Его использование с вектором неявно будет с:

vector char > vtr ;
vector char > :: const_iterator it = vtr. begin ( ) ;

Функция шаблона более применима к оператору begin () (второй оператор).

Видео:С++ 21. Const-, reverse-, output-итераторы. Потоковые итераторы.Скачать

С++ 21. Const-, reverse-, output-итераторы. Потоковые итераторы.

Доступ

Это возвращает размер контейнера. Пример вектора:

Возвращает true, если список пуст, или false в противном случае. Пример вектора:

На выходе 0 для ложного.

Видео:03 Инвалидация итераторовСкачать

03 Инвалидация итераторов

Доступ к диапазону

Существуют и другие функции шаблона, которые используют итераторы, которые вектор использует для решения задач диапазона. Диапазон — это последовательный набор элементов контейнера.

Это возвращает итератор, указывающий на первый элемент в списке. auto здесь означает, что возвращаемое значение определяется при оценке. Пример для вектора:

vector char > vtr ;
vector char > :: iterator it = vtr. begin ( ) ;
cout * it ‘ n ‘ ;

Результатом будет A. Итератор, возвращенный здесь, является итератором с произвольным доступом. Можно было вернуть постоянный итератор с произвольным доступом — см. Ниже.

Возвращает постоянный итератор, указывающий на последний элемент списка. Векторный код:

vector char > vtr ;
vector char > :: const_iterator it = vtr. end ( ) ;
— it ;
cout * it ‘ ‘ ;
— it ;
cout * it endl ;

На выходе будет «ED». Постоянный итератор можно увеличивать или уменьшать, но значение, на которое он указывает, нельзя изменить. Можно было вернуть нормальный итератор с произвольным доступом — см. Ниже.

Возвращает последнее значение в списке. rbegin () указывает на последний элемент списка, а не дальше последнего элемента списка, как это делает end (). Пример вектора:

vector char > vtr ;
vector char > :: reverse_iterator it = vtr. rbegin ( ) ;
cout * it ‘ ‘ ;
++ it ;
cout * it endl ;

Результатом будет: E D. С обратным итератором ++ имеет противоположный эффект для двунаправленного итератора.

Указывает непосредственно перед первым элементом списка. Пример вектора:

vector char > vtr ;
vector char > :: reverse_iterator it = vtr. rend ( ) ;
— it ;
cout * it ‘ ‘ ;
— it ;
cout * it endl ;

Выход — A B. С обратным итератором — имеет противоположный эффект для ++ двунаправленного итератора.

Под этим заголовком есть и другие функции шаблона — см. Ниже.

Видео:[C++] STL: VectorСкачать

[C++] STL: Vector

Вставить итераторы

reverse_iterator — это адаптер итератора, а не итератор. Итератор вставки также является адаптером итератора. Он удовлетворяет всем требованиям итератора вывода, а также его собственным требованиям. В C ++ он существует в трех формах: back_inserter, front_inserter и вставщик. У каждого из них есть свой конструктор.

back_inserter

Вставки сзади!
Важные прототипы:

Пример
вектора : вектор не имеет функции-члена вставки, которая вставляется сзади. Однако функцию-член push_back (t) можно увидеть так.

front_inserter

Вставки спереди!
Важные прототипы:

Пример
вектора : вектор не имеет функции-члена вставки, которая вставляется спереди. Вектор также не имеет функции-члена push_front (t).

Хорошая новость заключается в том, что у вектора есть функции-члены вставки, которые можно вставлять где угодно, в начало, внутри или в конец вектора.

inserter

Этот итератор будет вставлять в начало, внутри или в конец вектора.

vector char > vtr ;
vector char > :: iterator it = vtr. begin ( ) ;
it = it + 2 ;
vtr. insert ( it, ‘c’ ) ;

for ( int i = ; i vtr. size ( ) ; i ++ )
cout vtr [ i ] «, « ;
cout endl ;

Выражение вставки вектора:

Он вставляет элемент непосредственно перед указателем (им), на который он указывает.

Видео:Базовый курс С++ Часть #81. Вектор std::vectorСкачать

Базовый курс С++ Часть #81. Вектор std::vector

Move Iterator

Move_iterator также является адаптером итератора. Следующая программа похожа на пример из спецификации C ++:

#include
#include

#include
using namespace std ;

int main ( )
<
list char > chs ;
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 = ; i vtr. size ( ) ; i ++ )
cout vtr [ i ] «, « ;
cout endl ;

Исходный список Содержание:
A, B, C, D, E,

Векторный контент:
A, B, C, D, E,

Этот итератор преобразует исходное значение в rvalue перед тем, как поместить его в место назначения.

Видео:17. Спецификации исключений. Итераторы, виды итераторов.Скачать

17. Спецификации исключений. Итераторы, виды итераторов.

Заключение

Основными итераторами в C ++ являются итератор ввода, итератор вывода, итератор прямого действия, двунаправленный итератор и итератор произвольного доступа. В стандартной библиотеке C ++ есть несколько шаблонов функций, которые используют эти итераторы. Вектор использует эти итераторы через шаблоны функций. У вектора есть разные имена для некоторых из этих итераторов. Существуют также адаптеры итератора: reverse_iterator, адаптер итератора и move_iterator. Также существуют несколько вариантов итераторов. Достаточно включить в программу все эти функции. После понимания роли этих итераторов, адаптеров и шаблонов функций, которые их используют, использование итераторов с векторами становится интуитивно понятным.

Видео:STL: контейнеры, алгоритмы, итераторы, умные указателиСкачать

STL: контейнеры, алгоритмы, итераторы, умные указатели

Итераторы в C++: введение

Всем привет! Изучая контейнеры STL мы использовали новый вид переменных — итераторы. Так давайте узнаем, зачем ими пользуются?

Видео:Передача массива в функцию. Как передать массив в функцию. C++ для начинающих. Урок #35.Скачать

Передача массива в функцию. Как передать массив в функцию. C++ для начинающих. Урок #35.

Что такое итератор

Итератор — это такая структура данных, которая используется для обращения к определенному элементу в контейнерах STL. Обычно из используют с контейнерами set , list , а у вектора для этого применяют индексы.

Кстати по мере того, как мы будем изучать итераторы, вам все больше будет казаться, что итераторы и есть указатели (это мы разберем ниже).

Видео:Лекция 30. Реализация итераторов. Адаптеры над итераторамиСкачать

Лекция 30. Реализация итераторов. Адаптеры над итераторами

Как создать итератор

Для создания итератора мы должны с самого начала программы подключить библиотеку .

Далее для его создании нам потребуется использовать вот эту схему:

  • — указываем требуемый контейнер, на который и будет ссылаться итератор. Например map , vector , list .
  • — указываем тип контейнера.

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

Видео:Программирование на С++. Урок 71. Пример работы с вектором. Двумерный вектор.Скачать

Программирование на С++. Урок 71. Пример работы с вектором. Двумерный вектор.

Методы начала и конца контейнеров

У каждого контейнера имеются два метода, которые, как указатели передают итератору начало или конец контейнера — begin() и end().

  • Метод begin() отправит итератор на начала контейнера.
  • А метод end() отправит на конец. А если точнее, то на одну ячейку больше последней. Если мы попытаемся вывести эту ячейку у нас появятся проблемы с компилятором 🙂 .

Их мы можем использовать даже без подключения библиотеки , что очень удобно.

Также при инициализации итератора мы можем с самого начала написать, куда он будет указывать:

Видео:Контейнеры Vector и List. Введение в современный C++. Семантика переносов. Лямбда-функции. Л №13-14Скачать

Контейнеры Vector и List. Введение в современный C++. Семантика переносов. Лямбда-функции. Л №13-14

Итератор на vector

Для итератора на vector вы можете:

  • Выполнять операцию разыменования (обращаться к значению элемента на которое указывает итератор), как мы это делали с указателем.
  • Использовать инкремент ( it++, ++it ) и декремент ( it—, —it ).
  • Применять арифметические операции. Так например мы можем сместить итератор на пять ячеек в право, вот так:
  • Передать переменной разницу итераторов.

Но о использовании арифметических и сравнительных операциях ( > , , == ) с двумя итераторами, вам нужно кое что знать.

Использовать выше сказанные операции можно только с идентичными итераторами, которые указывают на одинаковый контейнер и тип.

Есть исключение из правил — если вы создадите два одинаковых итератора на map то при сравнивании они не будут одинаковы.

Например, если мы создали два итератора на один и тот же контейнер, но указали для них разный тип данных и решили использовать выше сказанные операции — то компилятор начнет ругаться.

Видео:Потоковый ввод вывод в файл c++. Перегрузка операторов. Изучение С++ для начинающих. Урок #119Скачать

Потоковый ввод вывод в файл c++. Перегрузка операторов. Изучение С++ для начинающих. Урок #119

Итератор на list, set, map

Для итераторов на list , set , map немного урезан функционал. Так вы не можете:

  • Использовать арифметические операции.
  • Применять операции сравнения ( > и ):

Все остальное можно использовать:

  • Применять инкремент и декремент.
  • Использовать операцию разыменования.
  • Сравнивать два итератора на равенство и неравенства:

Кстати использовать арифметические операции, чтобы увеличить итератор на один, как это делает инкремент — нельзя.

Но вы можете сказать: «Так что мы можем двигать итератор только на один элемент? Это же неудобно!» . Да было бы совсем не гибко со стороны C++ делать вот такое, но они позаботились и создали функцию — advanсe() , она заменяет операции увеличения и уменьшения над итераторами.

Вот как она работает:

  • — сюда мы должны указать итератор, который и нужно изменить.
  • — тут мы должны вписать число на которое должны увеличить или уменьшить итератор.

Если мы увеличиваем итератор, то используем оператор + к числу. Но можно и просто записать число без оператора + .

Если же нужно уменьшить итератор, то мы добавляем оператор — .

Как работают итераторы

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

  • В строке 10: создали вектор name_vector .
  • Дальше в последующих трех строках занимаемся его заполнением.
  • В строке 16: создали итератор под именем it .
  • В цикле for мы написали, что итератор указывает на последнюю ячейку вектора. С помощью вот такой не замысловатой конструкции :

Выше мы говорили, что метод end() указывает на одну ячейку больше последней. Поэтому, чтобы обратится к последнему элементу в векторе нам понадобилось отнять 1.

  • Используя операцию разыменования, в теле цикла, мы вывели все элементы.

Вы наверняка заметили, что мы выводим элементы задом наперед:

Важно знать! Если мы захотели выполнить операцию разыменования для ячейки, у которой индекс больше итератора на 5, то это сделать нужно именно так:

Если мы сделаем так, то мы выведем сумму ячейки на которую указывает итератор и пяти. А хотели же прибавить к итератору пять и применить операцию разыменования.

Все потому что, операция разыменования * происходит быстрее, чем операция присваивание. У этих операций совсем разный приоритет использования. У этой * больше, а у этой + меньше.

Итератор это не указатель

Сейчас после всего узнанного многие могут подумать, что итераторы это и есть указатели. Так как очень много общего между ними.

  • Итератор, как и указатель указывает на какую-то ячейку, а в указателе может храниться адрес ячейки динамического массива.
  • Чтобы обратится к значению ячейки мы применяем операцию разыменования.

Да итератор это усовершенствованная версия указателя, которая только работает с контейнерами. В некоторых языках указатель называют итератором, но это не значит, что он и есть указатель в C++.

Чтобы удостовериться в том, что итератор это не указатель давайте проверим это в программе ниже.

Поделиться или сохранить к себе: