C++/Iteratory: Różnice pomiędzy wersjami

Usunięta treść Dodana treść
Usunięcie błędnych informacji; Korzystając z iteratorów nadal można przekroczyć zakres kontenera. Iterator może wskazywać na niepoprawny element (np. iterator zwracany przez funkcje/metody ::end(), ::rend()).
Nie podano opisu zmian
Linia 5:
 
Istnieją pewne analogie między iteratorem a wskaźnikiem. Przede wszystkim znajomo wyglądają wyrażenia:
<sourcesyntaxhighlight lang="cpp">
*nasz_iterator // wartością jest element pojemnika wskazywany przez iterator nasz_iterator
wart = *nasz_iter // podstawienie wartości elementu pod zmienną wart
*nasz_iterator = wart // podstawienie wartości zmiennej w miejsce pojemnika wskazane przez nasz_iterator
</syntaxhighlight>
</source>
Umożliwia nam to przeciążony '''operator*''' , jak i '''operator=''' dzięki któremu możemy pod iterator podstawiać inne wartości.
 
Linia 15:
* '''Iteratory wejścia:'''
Taki iterator może odczytać wartość elementu, na który wskazuje, o ile nie wskazuje przekroczenia zakresu – end(). Musi posiadać domyślny konstruktor, konstruktor kopiujący oraz operatory =, ==, !=, ++. Odczytać wartość można:
<sourcesyntaxhighlight lang="cpp">
wart = *iterator; // poprawne użycie iteratora wejścia
*iterator = wartosc; // niepoprawne użycie iteratora wejścia- nie może zapisywać
</syntaxhighlight>
</source>
 
Można inkrementować iterator – aby wskazywał następny składnik:
<sourcesyntaxhighlight lang="cpp">
iterator++ lub ++iterator
</syntaxhighlight>
</source>
 
 
Linia 29:
Ten typ iteratora umożliwia tylko zapis wartości do danego składnika – odczyt jest niemożliwy. Musi posiadać domyślny konstruktor, konstruktor kopiujący oraz operatory =, ++.
np.
<sourcesyntaxhighlight lang="cpp">
*iterator = wartosc; // poprawnie
wartosc = *iterator; // błędnie – próbujemy odczytać
</syntaxhighlight>
</source>
 
 
Linia 47:
 
Sposób użycia iteratora bezpośredniego dostępu: ''(załóżmy ze nasz iterator wskazuje już składnik n-ty)''
<sourcesyntaxhighlight lang="cpp">
iterator += 5; // teraz wskazuje (n+5)-ąty składnik
iterator++; // teraz wskazuje (n+6)-ty składnik
*iterator[n] = wartosc; // przypisujemy n-temu składnikowi wartosc
</syntaxhighlight>
</source>
 
== Użycie w poszczególnych kontenerach (z przykładami) ==
Linia 60:
Poruszanie się za pomocą iteratorów po kolejnych składowych może odbywać się na dwa sposoby:<br>
1) '''w przód''' - czyli od początku do końca np.:
<sourcesyntaxhighlight lang="cpp">
kontener<typ kontenera>::iterator iter; // iterator do przodu
</syntaxhighlight>
</source>
początek struktury wyznacza metoda begin(); zaś koniec end();
 
2) '''od końca''' - czyli od końca do początku np.:
<sourcesyntaxhighlight lang="cpp">
kontener<typ kontenera>::reverse_iterator iter; // iterator od końca
</syntaxhighlight>
</source>
skanować możemy od <tt>rbegin();</tt> do <tt>rend();</tt>, co można utożsamiać z odwróconym początkiem i odwróconym końcem.
 
Linia 77:
 
Przykład:
<sourcesyntaxhighlight lang="cpp">
#include <iostream>
#include <vector>
Linia 98:
return 0;
}
</syntaxhighlight>
</source>
Program spowoduje wyświetlenie kolejnych elementów pojemnika:
1
Linia 105:
 
Metody begin() i end() skonstruowane są do przeglądania wektora od początku do końca. Co jeśli chcemy działać na składowych wektora w odwrotnej kolejności? Nie ma problemu. Istnieje bowiem metoda '''rbegin()''', która zwraca odwrócony iterator wskazujący na ostatni element pojemnika (mówi się także, że jest to odwrócony początek). Odwołuje się on do elementu bezpośrednio poprzedzającego iterator wskazywany przez end. Jest to odwrócony iterator bezpośredniego dostępu. Mamy także metodę '''rend()''', która zwraca odwrócony iterator do elementu odwołującego się do elementu bezpośrednio poprzedzającego pierwszy element kontenera wector (zwany także odwróconym końcem). rend() wskazuje miejsce bezpośrednio poprzedzające składnik do którego odwoływałby się begin(). Oto przykład:
<sourcesyntaxhighlight lang="cpp">
#include <iostream>
#include <vector>
Linia 125:
return 0;
}
</syntaxhighlight>
</source>
Wykonanie programu spowoduje wyświetlenie składników kontenera w odwrotnej kolejności:
3
Linia 138:
Używanie iteratorów w pętli for skutkuje dość długim (i w opinii niektórych - mało czytelnym) kodem. Czasami, programiści ułatwiają sobie życie stosując makro FOREACH:
 
<sourcesyntaxhighlight lang="cpp">
#define VAR(v,n) typeof(n) v=(n)
#define FOREACH(i,c) for(VAR(i,(c).begin());i!=(c).end();++i)
</syntaxhighlight>
</source>
 
Użycie w kodzie:
<sourcesyntaxhighlight lang="cpp">
vector<int> v;
v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4);
Linia 151:
cout << *it << endl;
}
</syntaxhighlight>
</source>
Powyższy kod wyprowadza na standardowe wyjście zwartość wektora "v".
Linia 158:
{{Porada|
W C++11 wprowadzono pętlę ''for'' opartą na zakresie (ang. ''range-based for loop''), dzięki czemu powyższy kod można uprościć do:
<sourcesyntaxhighlight lang="cpp">
vector<int> v;
v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4);
Linia 165:
cout << x << endl;
}
</syntaxhighlight>
</source>
}}
 
Linia 172:
 
Przykład:
<sourcesyntaxhighlight lang="cpp">
#include <iostream>
#include <list>
Linia 210:
return 0;
}
</syntaxhighlight>
</source>
Wynikiem działania programu będzie:
<!-- NIE ZMIENIAĆ lista od tylu: � c b --->
Linia 223:
===Zbiory===
Iterator w zbiorach działa jak w innych kontenerach. Iterator działający na zbiorze jest dwukierunkowy – możemy więc korzystać ze wszystkich operatorów przeciążonych dla iteratora dwukierunkowego. Dodatkowo (jak z własności zbioru wynika) należy wspomnieć, że metoda '''begin()''' daje dostęp iteratorowi do pierwszego elementu zbioru, który równocześnie posiada najniższy klucz. W zbiorach możemy także korzystać z odwróconych iteratorów.
<sourcesyntaxhighlight lang="cpp">
#include<iostream>
#include<set>
Linia 241:
return 0;
}
</syntaxhighlight>
</source>
Wynikiem pracy programu będzie wypisanie cyfr:
1