Historia pytania:
Iterator pojawił się w STL w C++98, co pozwoliło na abstrakcję od konkretnych struktur danych, zapewniając zunifikowany dostęp do elementów kontenera. Wraz z przyjęciem C++20 dodano standard ranges, co dalej zwiększyło czytelność i bezpieczeństwo pracy z kontenerami.
Problem:
Niepoprawna praca z iteratorami może prowadzić do błędów w czasie wykonywania: wyjście poza kontener, unieważnienie po zmianach. Wsparcie dla różnych rodzajów iteratorów prowadzi do nieprzewidywalnych zachowań, jeśli są mylone ze sobą. Praca "ręcznie" z begin()/end() wymaga dyscypliny.
Rozwiązanie:
Używać typu iteratora, który odpowiada możliwościom kontenera (na przykład, random access tylko w przypadku vector/deque/array). Nie przechowywać unieważnionych iteratorów. W nowoczesnych zadaniach częściej używać znormalizowanych ranges i algorytmów.
Przykład kodu:
#include <vector> #include <algorithm> #include <iostream> #include <ranges> int main() { std::vector<int> vec{1, 2, 3, 4, 5}; // Iteracja przez iterator for (auto it = vec.begin(); it != vec.end(); ++it) { std::cout << *it << " "; } // Iteracja przez zakres for (int x : vec | std::ranges::views::filter([](int v){return v % 2 == 0;})) { std::cout << x << " "; } return 0; }
Kluczowe cechy:
Co się stanie z iteratorem std::vector po wywołaniu push_back?
Jeśli po push_back pojemność kontenera wzrasta (rebalance), wszystkie stare iteratory i odniesienia stają się nieprawidłowe. Po push_back bez zmiany pojemności iteratory są zachowane. Bezpieczniej jest nie przechowywać iteratorów między modyfikacjami.
Czym różni się iterator random-access od bidirectional?
Random-access obsługuje arytmetykę (it + n) i dostęp przez indeks (it[n]), a bidirectional – tylko ++ i --. Nie wszystkie kontenery STL obsługują random-access.
Czy standardowe algorytmy STL mogą działać z zwykłymi wskaźnikami?
Tak, ponieważ wskaźnik w C++ w pełni odpowiada wymaganiom random-access iterator.
W pętli po std::list programista bezpośrednio zmienia kontener metodą erase, nie aktualizując iteratora, co prowadzi do błędu czasu wykonywania.
Zalety:
Wady:
Przed zmianą kontenera zawsze zapisuje się następny iterator. Używa standardowych algorytmów erase-remove idiom dla wektorów lub list::remove_if dla list.
Zalety:
Wady: