Как написать свой итератор c
Перейти к содержимому

Как написать свой итератор c

  • автор:

Как создать свой итератор для вектора в шаблонном классе?

Есть задание, написать шаблонный класс контейнер, в котором данные должны храниться в виде одной из STL коллекций. Я выбрал хранить их в std::vector.
Мне нужно написать свой двунаправленный итератор, в котором будет перегружен оператор инкремента (++), так, чтобы итератор пробегался по вектору и брал каждый третий элемент. Проблема заключается в том, что как бы я не пробовал его написать, ничего не получается с моим уже написанным классом.
Там у меня есть метод printEachThirdElement, который как раз занимается выводом каждого третьего элемента вектора, но это нужно реализовать как свой итератор. Прошу помощи.

Код шаблонного класса

#include #include #include template class MyVector < public: MyVector() : vector() < >MyVector(const T& value) : vector() < vector.push_back(value); >void info() const < std::cout std::cout std::int32_t size() const < return vector.size(); >void addElement(const T& value) < vector.push_back(value); >void removeElements(const T& value) < vector.erase(std::remove(vector.begin(), vector.end(), value), vector.end()); >void printEachThirdElement() const < for (auto i = vector.begin() + 2; i < vector.end(); i+=3) < std::cout std::cout private: std::vector vector; >;

Код функции main()

int main() < MyVectorvInt; vInt.addElement(5); vInt.addElement(6); vInt.addElement(7); vInt.addElement(5); vInt.addElement(15); vInt.addElement(12); vInt.addElement(5); vInt.addElement(51); vInt.addElement(666); vInt.addElement(5); vInt.addElement(15); vInt.addElement(12); vInt.addElement(5); vInt.addElement(51); vInt.addElement(666); std::cout
  • Вопрос задан более двух лет назад
  • 457 просмотров

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

обложка статьи

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

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

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

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

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

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

#include 

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

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

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

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

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

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

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

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

vector int> i_am_vector; vector int> :: iterator it = i_am_vector.begin();

Итератор на vector

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

  • Выполнять операцию разыменования (обращаться к значению элемента на которое указывает итератор), как мы это делали с указателем.
int x = *it;
  • Использовать инкремент ( it++, ++it ) и декремент ( it--, --it ).
  • Применять арифметические операции. Так например мы можем сместить итератор на пять ячеек в право, вот так:
it += 5;
  • Сравнивать на равенства.
if (it == it2)  ...
  • Передать переменной разницу итераторов.
int x = it - it2;

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

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

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

vector int> vector_first; vector double> vector_second; vector int> :: iterator it = vector_first.begin(); vector double> :: iterator it2 = vector_second.begin(); if (it == it2)  // ошибка! cout  <"it == it2"; >

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

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

  • Использовать арифметические операции.
it += 5; // it *= 2; // it /= 3; // ошибка it -= 5; //
  • Применять операции сравнения ( > и < ):
if (it > it_second)  ... // // ошибка if (it  it_second)  ... //

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

  • Применять инкремент и декремент.
it--; // все it++; // нормально!
  • Использовать операцию разыменования.
cout  *it; *it += 5;
  • Сравнивать два итератора на равенство и неравенства:
if (it == it_second)  ... // // правильно if (it != it_second)  ... //

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

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

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

advance(итератор>, значение>);
  • - сюда мы должны указать итератор, который и нужно изменить.
  • - тут мы должны вписать число на которое должны увеличить или уменьшить итератор.

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

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

advanсe(it, 5); // сместили на 5 ячеек

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

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

#include #include #include using namespace std; int main()  setlocale(0, ""); vector name_vector; name_vector.push_back(3); name_vector.push_back(4); name_vector.push_back(6); vector int> :: iterator it; for (it = name_vector.end() - 1; it >= name_vector.begin(); it--)  cout  <*it  <" "; > system("pause"); return 0; >
  • В строке 10: создали вектор name_vector .
  • Дальше в последующих трех строках занимаемся его заполнением.
  • В строке 16: создали итератор под именем it .
  • В цикле for мы написали, что итератор указывает на последнюю ячейку вектора. С помощью вот такой не замысловатой конструкции :
it = name_vector.end() - 1;

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

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

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

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

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