Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <stdio.h>
- #include <tchar.h>
- #include <iostream>
- #include <vector>
- #include <list>
- #include <forward_list>
- #include <iterator>
- // CLASS_06: iteratory
- // Funkcja drukująca zawartość dowolnego kontenera, korzystająca z iteratorów
- template <typename IterT>
- void Print(IterT b, IterT e)
- {
- for (auto it = b; it != e; ++it) {
- std::cout << *it << ' ';
- }
- std::cout << std::endl;
- }
- int _tmain(int argc, _TCHAR* argv[])
- {
- std::cout << "====== EXAMPLE 1 forward_iterator ======" << std::endl << std::endl;
- // tworzymy listę jednokierunkową i inicjalizujemy jej zawartość w pętli
- std::forward_list<int> fl;
- for (int i = -3; i < 9; ++i) {
- fl.push_front(i);
- }
- // wypisujemy zawartość listy za pomocą pętli używającej iteratorów
- // przykład użycia "cbegin" i "cend", które zwracają "const_iterator"
- // użycie "begin" i "end" oraz deklaracja "it" za pomocą "auto" nie gwarantują, że "it" będzie "const_iterator"
- // jeżeli nie potrzebujemy nadpisywać zawartości kontenera, to dobrą praktyką jest użycie "const_iterator"
- std::cout << "forward_list: ";
- for (auto pos = fl.cbegin(); pos != fl.cend(); ++pos) {
- std::cout << *pos << ' ';
- }
- std::cout << std::endl << std::endl;
- // w przypadku iteratora jednokierunkowego dostępne są operacje:
- // - operator dereferencji: * (linia 35)
- // - operatory porównania: != == (linia 34)
- // - operator inkrementacji: ++ (linia 34)
- std::cout << "====== EXAMPLE 2 bidirectional_iterator ======" << std::endl << std::endl;
- // tworzymy listę i inicjalizujemy jej zawartość w pętli
- std::list<int> l;
- for (int i = -3; i < 9; ++i) {
- l.push_back(i);
- }
- // wypisujemy zawartość listy za pomocą pętli używającej iteratorów
- std::cout << "list: ";
- for (auto pos = l.cbegin(); pos != l.cend(); ++pos) {
- std::cout << *pos << ' ';
- }
- std::cout << std::endl << std::endl;
- // w przypadku iteratora dwukierunkowego dostępne są operacje jak dla forward_iterator oraz:
- // - operator dekrementacji
- std::cout << "====== EXAMPLE 3 random_access_iterator ======" << std::endl << std::endl;
- // tworzymy vektor i inicjalizujemy jego zawartość w pętli
- std::vector<int> v;
- for (int i = -3; i < 9; ++i) {
- v.push_back(i);
- }
- // wypisujemy co drugi element wektora za pomocą pętli używającej iteratorów
- std::cout << "vector: ";
- for (auto pos = v.cbegin(); pos < v.cend() && std::next(pos) < v.cend(); pos += 2) {
- std::cout << *pos << ' ';
- }
- std::cout << std::endl << std::endl;
- // w przypadku iteratora dwukierunkowego dostępne są operacje jak dla bidirectional_iterator oraz:
- // - operatory arytmetyczne: + - += -= (linia 66)
- // - operatory mniejszości/większości: < > <= >= (linia 66)
- // random_access_iterator ma takie same właściwości jak surowy wskaźnik!
- // Zamiana deklaracji zmiennej v z "vector" na "list" spowoduje, że kod się nie skompiluje,
- // bo iterator listy nie ma właściwości "random_access_iterator".
- // Pisząc kod dobrą praktyką jest używanie minimalnej wspólnej funkcjonalności iteratorów,
- // wtedy kod jest bardziej uniwersalny.
- // Wszystkie kontenery STL posiadają iteratory kategorii przynajmniej "forward_iterator".
- std::cout << "====== EXAMPLE 4 distance/advance/next/prev ======" << std::endl << std::endl;
- std::cout << "number/size: " << l.size() << std::endl;
- // funkcja "distance" zwraca liczbę elementów między dwoma iteratorami
- std::cout << "number/distance: " << std::distance(l.begin(), l.end()) << std::endl;
- // Uwaga: musi być możliwe przejście w przód z pierwszego iteratora do drugiego, inaczej zachowanie jest niezdefiniowane!
- //std::cout << "number/distance " << std::distance(cont.end(), cont.begin()) << std::endl; BLĄD!
- // funkcja "advance" pozwala na przesunięcie iteratora żeby pokazywał na inny element
- auto it1 = l.begin();
- auto it2 = l.end();
- std::advance(it1, 3); // przesunięcie o 3 do przodu
- std::advance(it2, -2); // przesunięcie o 2 do tyłu
- std::cout << "subset number/distance: " << std::distance(it1, it2) << std::endl;
- std::cout << "sum of adjacent elements: ";
- // wersja z dwoma iteratorami pomocniczymi:
- auto pos2 = l.begin(); // "pos2" zaincjalizowane jako "begin"
- auto pos1 = pos2++; // post-inkrementacja! "pos1" będzie równe "begin", a "pos2" będzie wskazywać na drugi element w sekwencji
- while (pos1 != l.end() && pos2 != l.end()) {
- std::cout << *pos1 + *pos2 << ' ';
- ++pos1;
- ++pos2;
- }
- std::cout << std::endl;
- std::cout << "sum of adjacent elements: ";
- // wersja z funkcją pomocniczą "next", wystarczy tylko jeden iterator
- auto pos3 = l.begin();
- while (pos3 != l.end() && std::next(pos3) != l.end()) {
- std::cout << *pos3 + *std::next(pos3) << ' ';
- ++pos3;
- }
- std::cout << std::endl << std::endl;
- // Używając funkcji "distance" i "advance" należy pamiętać o tym, że dla różnych kategorii iteratorów mają różną złożoność:
- // - dla random_access_iterator - stały czas wykonania
- // - dla bidirectional_iterator i forward_iterator - liniowy czas wykonania
- std::cout << "====== EXAMPLE 5 reverse iterator ======" << std::endl << std::endl;
- // przykładowy kontener
- std::vector<int> coll = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
- // wypisujemy zawartość od początku do końca
- for (auto it = coll.begin(); it != coll.end(); ++it) {
- std::cout << *it << ' ';
- }
- std::cout << std::endl;
- // wypisujemy zawartość od końca za pomocą reverse iterator
- for (auto it = coll.rbegin(); it != coll.rend(); ++it) {
- std::cout << *it << ' ';
- }
- std::cout << std::endl;
- // tymczasowy iterator, przechowujący pozycję w kontenerze
- std::vector<int>::const_iterator pos;
- // wyszukujemy pozycji elementu o wartości 5
- pos = std::find(coll.cbegin(), coll.cend(), 5);
- std::cout << "pos: " << *pos << std::endl;
- // zamieniamy iterator "pos" na reverse iterator
- std::vector<int>::const_reverse_iterator rpos(pos);
- std::cout << "rpos: " << *rpos << std::endl;
- // reverse iterator wskazuje na tą samą pozycję fizyczną w kontenerze, ale na sąsiednią pozycję logiczną,
- // ponieważ pozwala to zachować definicję zakresu iteratorów jako przedziału jednostronnie domkniętego
- // bez ingerencji w kontener
- // metoda "base()" pozwala na odzyskanie iteratora "do przodu" z iteratora odwrotnego (reverse iterator)
- std::vector<int>::const_iterator rrpos;
- rrpos = rpos.base();
- std::cout << "rrpos: " << *rrpos << std::endl << std::endl;
- std::cout << "====== EXAMPLE 6 insert iterator ======" << std::endl << std::endl;
- // tworzymy przykładowy kontener
- std::vector<int> vec = { 1, 2, 3 };
- // używamy insertera (insert iterator) w celu wstawienia nowych elementów
- // insert iterator zamienia operację nadpisania elementu (przypisania nowej wartości) operacją dodania nowego elementu
- // "back_inserter" dodaje nowy element na końcu kontenera, "front_inserter" na początku, a "inserter" w żądanej pozycji
- std::back_inserter(vec) = 44;
- std::back_inserter(vec) = 55;
- Print(vec.begin(), vec.end());
- // użycie insertera w celu wypełnienia listy w locie elementami z wektora "v"
- std::list<int> lst;
- std::copy(vec.begin(), vec.end(), std::front_inserter(lst));
- Print(lst.begin(), lst.end());
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement