An Iterator to obiekt, który może przechodzić (iterować po) klasie kontenera bez konieczności znajomości przez użytkownika kontenera wdrożony. W przypadku wielu klas (szczególnie list i klas asocjacyjnych) iteratory są głównym sposobem uzyskiwania dostępu do elementów tych klas.
Iterator najlepiej jest wizualizować jako wskaźnik do danego elementu w kontenerze, z zestawem przeciążonych operatorów zapewniających zestaw dobrze zdefiniowanych funkcji:
- Operator* -- Wyłuskanie iteratora zwraca element, którym aktualnie się iterator zajmuje wskazując na.
- Operator++ -- Przenosi iterator do następnego elementu w kontenerze. Większość iteratorów umożliwia również
Operator--przejście do poprzedniego elementu. - Operator== i Operator!= -- Podstawowe operatory porównania służące do określenia, czy dwa iteratory wskazują na ten sam element. Aby porównać wartości, na które wskazują dwa iteratory, należy najpierw wyrejestrować iteratory, a następnie użyć operatora porównania.
- Operator= -- Przypisz iterator do nowej pozycji (zazwyczaj początek lub koniec elementów kontenera). Aby przypisać wartość elementu, na który wskazuje iterator, należy najpierw wyrejestrować iterator, a następnie użyć operatora przypisania.
Każdy kontener zawiera cztery podstawowe funkcje składowe do użycia z Operator=:
- begin() zwraca iterator reprezentujący początek elementów w kontener.
- end() zwraca iterator reprezentujący element znajdujący się tuż za końcem elementów.
- cbegin() zwraca stały iterator (tylko do odczytu) reprezentujący początek elementów w kontenerze.
- cend() zwraca stałą iterator (tylko do odczytu) reprezentujący element znajdujący się tuż za końcem elementów.
Może wydawać się dziwne, że end() nie wskazuje ostatniego elementu na liście, ale robi się to przede wszystkim po to, aby ułatwić wykonywanie pętli: iteracja po elementach może być kontynuowana, aż iterator dotrze do end() i wtedy będziesz wiedział, że skończyłeś.
W końcu wszystkie kontenery udostępniają (co najmniej) dwa typy iterators:
- container::iterator zawiera iterator odczytu/zapisu
- container::const_iterator zapewnia iterator tylko do odczytu
Przyjrzyjmy się kilku przykładom użycia iteratorów.
Iteracja po wektor
#include <iostream>
#include <vector>
int main()
{
std::vector<int> vect;
for (int count=0; count < 6; ++count)
vect.push_back(count);
std::vector<int>::const_iterator it; // declare a read-only iterator
it = vect.cbegin(); // assign it to the start of the vector
while (it != vect.cend()) // while it hasn't reach the end
{
std::cout << *it << ' '; // print the value of the element it points to
++it; // and iterate to the next element
}
std::cout << '\n';
}To wypisuje następujący komunikat:
0 1 2 3 4 5
Iteracja po liście
Teraz zróbmy to samo z listą:
#include <iostream>
#include <list>
int main()
{
std::list<int> li;
for (int count=0; count < 6; ++count)
li.push_back(count);
std::list<int>::const_iterator it; // declare an iterator
it = li.cbegin(); // assign it to the start of the list
while (it != li.cend()) // while it hasn't reach the end
{
std::cout << *it << ' '; // print the value of the element it points to
++it; // and iterate to the next element
}
std::cout << '\n';
}Wypisuje:
0 1 2 3 4 5
Zauważ, że kod jest prawie identyczny jak w przypadku wektorów, mimo że wektory i listy mają prawie całkowicie różne wewnętrzne implementacje!
Iteracja po zbiorze
W poniższym przykładzie: utworzymy zbiór z 6 liczb i użyjemy iteratora do wydrukowania wartości w zestawie:
#include <iostream>
#include <set>
int main()
{
std::set<int> myset;
myset.insert(7);
myset.insert(2);
myset.insert(-6);
myset.insert(8);
myset.insert(1);
myset.insert(-4);
std::set<int>::const_iterator it; // declare an iterator
it = myset.cbegin(); // assign it to the start of the set
while (it != myset.cend()) // while it hasn't reach the end
{
std::cout << *it << ' '; // print the value of the element it points to
++it; // and iterate to the next element
}
std::cout << '\n';
}Ten program daje następujący wynik:
-6 -4 1 2 7 8
Zauważ, że chociaż zapełnianie zbioru różni się od sposobu wypełniania wektora i listy, kod używany do iteracji po elementach zbioru był zasadniczo identyczny.
Iteracja po mapie
Ten jest trochę trudniejszy. Mapy i multimapy przyjmują pary elementów (zdefiniowane jako std::pair). Do łatwego tworzenia par używamy funkcji pomocniczej make_pair(). std::pair umożliwia dostęp do elementów pary za pośrednictwem pierwszego i drugiego elementu członkowskiego. Na naszej mapie używamy pierwszego jako klucza, a drugiego jako wartości.
#include <iostream>
#include <map>
#include <string>
int main()
{
std::map<int, std::string> mymap;
mymap.insert(std::make_pair(4, "apple"));
mymap.insert(std::make_pair(2, "orange"));
mymap.insert(std::make_pair(1, "banana"));
mymap.insert(std::make_pair(3, "grapes"));
mymap.insert(std::make_pair(6, "mango"));
mymap.insert(std::make_pair(5, "peach"));
auto it{ mymap.cbegin() }; // declare a const iterator and assign to start of vector
while (it != mymap.cend()) // while it hasn't reach the end
{
std::cout << it->first << '=' << it->second << ' '; // print the value of the element it points to
++it; // and iterate to the next element
}
std::cout << '\n';
}Ten program generuje wynik:
1=banana 2=orange 3=grapes 4=apple 5=peach 6=mango
Zauważ tutaj, jak łatwo iteratory ułatwiają przechodzenie przez każdy element kontenera. Nie musisz się w ogóle przejmować tym, jak mapa przechowuje swoje dane!
Wnioski
Iteratory umożliwiają łatwe przechodzenie przez elementy klasy kontenera bez konieczności zrozumienia sposobu implementacji klasy kontenera. W połączeniu z algorytmami STL i funkcjami składowymi klas kontenerów iteratory stają się jeszcze potężniejsze. W następnej lekcji zobaczysz przykład użycia iteratora do wstawiania elementów do listy (który nie zapewnia przeciążonego operatora [] umożliwiającego bezpośredni dostęp do jego elementów).
Jeden punkt warty odnotowania: Iteratory muszą być implementowane dla poszczególnych klas, ponieważ iterator musi wiedzieć, w jaki sposób dana klasa jest implementowana. W ten sposób iteratory są zawsze powiązane z określonymi klasami kontenerów.

