Zasady unieważniania iteratora
Jakie są zasady unieważniania iteratorów dla kontenerów C++?
Najlepiej w formacie listy podsumowującej.
(uwaga: jest to wpis do Stack Overflow ' S C++ FAQ . Jeśli chcesz krytykować pomysł dostarczenia FAQ w tej formie, to post na meta, który rozpoczął to wszystko , byłby miejscem, aby to zrobić. Odpowiedzi na to pytanie są monitorowane w C++ chatroom , gdzie pomysł FAQ zaczął się w pierwszej kolejności, więc twój odpowiedź jest bardzo prawdopodobne, aby przeczytać przez tych, którzy wpadli na pomysł.)
4 answers
C++03 (Źródło: Iterator Unieważnia Reguły (C++03))
Wstawianie
kontenery sekwencyjne
-
vector
: nie ma to wpływu na wszystkie Iteratory i odniesienia przed punktem wstawiania, chyba że nowy Rozmiar kontenera jest większy niż poprzednia pojemność (w tym przypadku wszystkie Iteratory i odniesienia są unieważnione) [23.2.4.3 / 1] -
deque
: Wszystkie Iteratory i odwołania są unieważnione, chyba że wstawiony element jest na końcu (z przodu lub z tyłu) deque (w którym to przypadku wszystkie Iteratory są unieważnione, ale odniesienia do elementów nie mają wpływu) [23.2.1.3/1] -
list
: wszystkie Iteratory i odwołania nie mają wpływu [23.2.2.3 / 1]
kontenery asocjacyjne
-
[multi]{set,map}
: wszystkie Iteratory i odwołania nie mają wpływu [23.1.2 / 8]
Adaptery pojemników
-
stack
: dziedziczony z bazowego kontenera -
queue
: kontener bazowy -
priority_queue
: dziedziczony z bazowego kontenera
Kasowanie
kontenery sekwencyjne
-
vector
: każdy iterator i Referencja po punkcie Kasowania są unieważniane [23.2.4.3 / 3] -
deque
: Wszystkie Iteratory i odwołania są unieważniane, chyba że usunięte elementy są na końcu (z przodu lub z tyłu) deque (w tym przypadku unieważniane są tylko Iteratory i odniesienia do usuniętych elementów) [23.2.1.3/4] -
list
: unieważniane są tylko Iteratory i odwołania do usuniętego elementu [23.2.2.3 / 3]
kontenery asocjacyjne
-
[multi]{set,map}
: unieważniane są tylko Iteratory i odwołania do usuniętych elementów [23.1.2 / 8]
Adaptery pojemników
-
stack
: dziedziczony z bazowego kontenera -
queue
: dziedziczony z bazowego kontenera -
priority_queue
: Pojemnik
Zmiana rozmiaru
-
vector
: zgodnie z insert/erase [23.2.4.2 / 6] -
deque
: zgodnie z insert/erase [23.2.1.2 / 1] -
list
: zgodnie z insert/erase [23.2.2.2/1]
Uwaga 1
O ile nie zaznaczono inaczej (albo jawnie lub definiując funkcję w zakresie innych funkcji), wywołując funkcja członka kontenera lub przekazywanie kontener jako argument a funkcja biblioteki nie unieważnia Iteratory do, lub zmienić wartości, obiektów wewnątrz tego kontenera. [23.1/11]
Uwaga 2
W C++2003 nie jest jasne, czy Iteratory "end" podlegają powyższym regułom ; w każdym razie należy założyć, że tak jest (jak to ma miejsce w praktyce).
Uwaga 3
Zasady unieważniania wskaźników są sames jako zasady unieważniania odniesień.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:37
C++11 (Source: iterator (C++0x))
Wstawianie
kontenery sekwencyjne
-
vector
: nie ma to wpływu na wszystkie Iteratory i odniesienia przed punktem wstawiania, chyba że nowy Rozmiar kontenera jest większy niż poprzednia pojemność (w tym przypadku wszystkie Iteratory i odniesienia są unieważnione) [23.3.6.5 / 1] -
deque
: Wszystkie Iteratory i odwołania są unieważnione, chyba że wstawiony element jest na końcu (z przodu lub z tyłu) deque (w którym to przypadku wszystkie Iteratory są unieważnione, ale odniesienia do elementów nie mają wpływu) [23.3.3.4/1] -
list
: wszystkie Iteratory i odwołania nie mają wpływu [23.3.5.4 / 1] -
forward_list
: wszystkie Iteratory i odwołania bez wpływu (dotyczyinsert_after
) [23.3.4.5/1] -
array
: (n / a)
kontenery asocjacyjne
-
[multi]{set,map}
: Wszystkie Iteratory i odwołania pozostają nienaruszone [23.2.4/9]
kontenery asocjacyjne niesortowane
-
unordered_[multi]{set,map}
: wszystkie Iteratory unieważnione podczas ponownego rozmycia, ale odwołania nie mają wpływu [23.2.5 / 8]. Ponowne płukanie nie występuje, jeśli Wkładanie nie powoduje, że rozmiar pojemnika przekraczaz * B
, gdziez
jest maksymalnym współczynnikiem obciążenia iB
bieżącą liczbą łyżek. [23.2.5/14]
Adaptery pojemników
-
stack
: Pojemnik -
queue
: dziedziczony z podstawowego kontenera -
priority_queue
: dziedziczony z podstawowego kontenera
Kasowanie
kontenery sekwencyjne
- [23.3.6.5/3]: każdy iterator i Referencja w punkcie kasowania lub po nim są unieważniane [23.3.6.5 / 3]
-
deque
: wymazanie ostatniego elementu unieważnia tylko Iteratory i odwołania do usuniętych elementów oraz iteratora zakończonego; wymazanie pierwszego elementu unieważnia tylko Iteratory i odniesienia do usuniętych elementów; wymazanie wszelkich innych elementów unieważnia wszystkie Iteratory i odniesienia (w tym Iteratory przeszłe i końcowe) [23.3.3.4/4] -
list
: unieważniane są tylko Iteratory i odwołania do usuniętego elementu [23.3.5.4 / 3] -
forward_list
: unieważniane są tylko Iteratory i odwołania do usuniętego elementu (dotyczyerase_after
) [23.3.4.5/1] -
array
: (n / a)
asocjacyjny pojemniki
-
[multi]{set,map}
: unieważniane są tylko Iteratory i odwołania do usuniętych elementów [23.2.4 / 9]
niestandardowe pojemniki asocjacyjne
-
unordered_[multi]{set,map}
: unieważniane są tylko Iteratory i odwołania do usuniętych elementów [23.2.5 / 13]
Adaptery pojemników
-
stack
: dziedziczony z podstawowego kontenera -
queue
: dziedziczony z podstawowego kontenera -
priority_queue
: dziedziczenie z bazowego kontenera
Zmiana rozmiaru
-
vector
: jak na insert/erase [23.3.6.5 / 12] -
deque
: zgodnie z insert/erase [23.3.3.3 / 3] -
list
: zgodnie z insert/erase [23.3.5.3 / 1] -
forward_list
: zgodnie z insert/erase [23.3.4.5 / 25] -
array
: (n / a)
Uwaga 1
O ile nie zaznaczono inaczej (albo jawnie lub definiując funkcję w zakresie innych funkcji), wywoływanie funkcja członka kontenera lub przekazywanie kontener jako argument a funkcja biblioteki nie unieważnia Iteratory do, lub zmienić wartości, obiektów wewnątrz tego kontenera. [23.2.1/11]
Uwaga 2
Brak funkcji swap () unieważnia wszelkie odniesienia, wskaźniki lub Iteratory nawiązując do elementów kontenery są wymieniane. [Note: The end () iterator nie odnosi się do żadnego element, więc to może zostać unieważnione . - Uwaga końcowa] [23.2.1/10]
Uwaga 3
Inne niż powyższe zastrzeżenie dotyczące swap()
, nie jest jasne, czy Iteratory "końcowe" podlegają wyżej wymienionym regułom per-container ; w każdym razie powinieneś założyć, że tak.
Uwaga 4
vector
i wszystkienieuporządkowane kontenery asocjacyjne wspierają reserve(n)
, co gwarantuje, że nie nastąpi automatyczna zmiana rozmiaru przynajmniej do rozmiaru Pojemnik rośnie do n
. Należy zachować ostrożność w przypadku kontenerów asocjacyjnych nieuporządkowanych , ponieważ przyszły wniosek pozwoli na określenie minimalnego współczynnika obciążenia, co umożliwi ponowne załadowanie na insert
po wystarczającej ilości operacji erase
zmniejszy rozmiar kontenera poniżej minimum; gwarancję należy uznać za potencjalnie nieważną po erase
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:12
Warto chyba dodać, że iterator insert dowolnego rodzaju (std::back_insert_iterator
, std::front_insert_iterator
, std::insert_iterator
) jest gwarantowane, że pozostanie ważne tak długo, jak wszystkie wstawki są wykonywane przez ten iterator i nie wystąpi żadne inne zdarzenie unieważniające iterator.
Na przykład, gdy wykonujesz serię operacji wstawiania do std::vector
za pomocą std::insert_iterator
jest całkiem możliwe, że wektor doświadczy zdarzenia realokacji, które unieważni wszystkie Iteratory, które "wskazują" na ten wektor. Jednak insert iterator, o którym mowa, ma gwarancję, że pozostanie ważny, tzn. można bezpiecznie kontynuować sekwencję wstawek. Nie ma potrzeby martwić się o wyzwalanie realokacji wektorów.
Odnosi się to ponownie tylko do wstawiania wykonywanego przez iterator insert. Jeśli iterator-unieważnienie zdarzenia zostanie wywołane przez jakieś niezależne działanie na kontenerze, wtedy iterator insert również zostanie unieważniony zgodnie z ogólnymi zasadami.
Na przykład, to kod
std::vector<int> v(10);
std::vector<int>::iterator it = v.begin() + 5;
std::insert_iterator<std::vector<int> > it_ins(v, it);
for (unsigned n = 20; n > 0; --n)
*it_ins++ = rand();
Gwarantuje wykonanie prawidłowej sekwencji wstawek do wektora, nawet jeśli wektor "zdecyduje" się ponownie przydzielić gdzieś w środku tego procesu.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-23 18:54:43
Ponieważ to pytanie przyciąga tak wiele głosów i staje się FAQ, myślę, że lepiej byłoby napisać oddzielną odpowiedź, aby wspomnieć o jednej znaczącej różnicy między C++03 A C++11 w odniesieniu do wpływu operacji wstawiania std::vector
na ważność iteratorów i odniesień w odniesieniu do reserve()
i capacity()
, których najbardziej upvoted odpowiedź nie zauważył.
C++ 03:
Realokacja unieważnia wszystkie odwołania, wskaźniki i Iteratory nawiązując do elementy w sekwencji. Gwarantujemy, że nie realokacja odbywa się podczas wstawek, które następują po wywołaniu do reserve () do czasu, gdy wstawianie spowoduje, że rozmiar wektor większy niż rozmiar podany w ostatnim wywołaniu do reserve () .
C++11:
Realokacja unieważnia wszystkie odwołania, wskaźniki i Iteratory odwołując się do elementów w sekwencji. Gwarantujemy, że nie realokacja odbywa się podczas wstawek, które zdarzają się po wywołaniu do reserve () do czasu, gdy wstawianie spowoduje, że rozmiar wektor większy niż wartość capacity () .
Więc w C++03 nie jest to "unless the new container size is greater than the previous capacity (in which case all iterators and references are invalidated)
", Jak wspomniano w drugiej odpowiedzi, zamiast tego powinno być " greater than the size specified in the most recent call to reserve()
". Jest to jedna rzecz, którą C++03 różni się od C++11. W C++03 raz insert()
powoduje, że rozmiar wektora osiąga wartość określoną w poprzednim wywołaniu reserve()
(która może być mniejsza niż obecnie capacity()
ponieważ reserve()
może spowodować większe capacity()
niż oczekiwano), każde następne insert()
może spowodować realokację i unieważnić wszystkie Iteratory i odwołania. W C++11 tak się nie stanie i zawsze możesz zaufać capacity()
, aby wiedzieć z pewnością, że następna realokacja nie odbędzie się przed rozmiarem capacity()
.
Podsumowując, jeśli pracujesz z wektorem C++03 i chcesz mieć pewność, że realokacja nie nastąpi podczas wstawiania, jest to wartość argument, który wcześniej przekazałeś reserve()
, że powinieneś sprawdzić rozmiar, a nie wartość zwracaną wywołania capacity()
, w przeciwnym razie możesz się zaskoczyć ponowną alokacją" przedwczesne ".
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-08 11:59:45