2013-05-27 11 views
7

referencyjny http://www.careercup.com/question?id=17188673 przez chetan.j9Czy możemy przechowywać unordered_map <T> :: iterator?

void Insert(string s) { 
    if(IsElementPresent(s)) 
     return; 

    myMap[s] = myMapVector.size(); 
    unordered_map<string,int>::iterator it = myMap.find(s); 
    myMapVector.push_back(it);  
} 

Pytania> Czy możemy przechowywać iteratorem unordered_map dla późniejszego odzyskania? Na podstawie mojego zrozumienia iterator zostanie unieważniony po wstawieniu lub usunięciu elementu.

Dziękuję

+1

Miłym odniesieniem do unieważniania iteratora dla wszystkich kontenerów jest http: // stackoverflow.com/questions/6438086/iterator-invalidation-rules – JRG

Odpowiedz

5

Wstawienie elementu unieważnia wszystkie iteratory tylko jeśli wystąpi hashuje (tzn. Jeśli nowa liczba elementów jest większa lub równa max_load_factor()*bucket_count()). W przeciwnym razie nie zostaną unieważnione iteratory.

Usunięcie elementu powoduje tylko, że iteratory są usuwane z usuniętych elementów, a nie z innych niepowiązanych elementów.

Źródło: std::unordered_map::insert i std::unordered_map::erase.

Oczywiście te zasady dotyczą tylko std::unordered_map. Inne kontenery mogą mieć różne reguły unieważniania, to od Ciebie zależy, czy zajrzysz do dokumentacji.

+0

Ponieważ nie wiemy, kiedy nastąpi unieważnienie, implementacja 'insert' nie jest poprawna. Dobrze? – q0987

+0

@ q0987 Rzeczywiście wiemy, kiedy następuje unieważnienie (reguła jest całkiem jasna). Jeśli znasz maksymalną liczbę przedmiotów z wyprzedzeniem, możesz po prostu ['zarezerwować'] (http://pl.cppreference.com/w/cpp/container/unordered_map/reserve), a następnie możesz bezpiecznie przechowywać iteratory, nawet jeśli wstawiasz, o ile nie przekroczysz zarezerwowanego maksimum. Ale oczywiście, jeśli chcesz wstawić nieznaną liczbę przedmiotów, to zupełnie inna historia, a przechowywanie iteratorów byłoby złym pomysłem, gdy wciąż wstawiasz elementy. – syam

+2

Ściśle mówiąc, warunkiem rehashingu jest to, że liczba nowych elementów jest większa niż _lub równa_ formule, którą podałeś (lub, ponieważ mówimy liczby zmiennoprzecinkowe, lepiej używaj mniej niż i negacja zdania) . – jogojapan

14

@ odpowiedź Syam jest prawidłowa (+1), ale myślę, że jest to przydatne zacytować z jedynego wiarygodnego źródła, C++ 11 standardowa:

(§23.2.5/13) insert oraz emplace elementy nie mają wpływu na ważność odniesień do elementów kontenera, ale mogą unieważnić wszystkie iteratory do kontenera. Członkowie kasowania unieważniają tylko iteratory i odniesienia do wymazanych elementów.

(§23.2.5/14) insert i emplace użytkownicy nie mają wpływu na ważność iteratorami jeśli (N + N) < oo * A, gdzie N oznacza liczbę elementów w pojemniku przed operacją wkładki , n to liczba wstawionych elementów, B to liczba pojemników w pojemniku, a z to maksymalny współczynnik obciążenia kontenera.

(Aby umieścić to w kontekście:. §23.2.5 jest sekcja na nieuporządkowanych kontenerów asocjacyjnych, więc ma ona zastosowanie do std::unordered_set, std::unordered_map, std::unordered_multiset i std::unordered_multimap) To znaczy:

  1. Jeśli chcesz wstawić n elementów w produkt unordered_map nazywa hash można sprawdzić, czy

    hash.size() + n < hash.max_load_factor() * hash.bucket_count() 
    

    jest prawdziwe. Jeśli jest false, wszystkie iteratory zostaną unieważnione podczas wstawiania. Jeśli true, iteratory pozostaną ważne.

  2. Nawet jeśli w tej operacji translatory zostaną unieważnione, odniesień do samych elementów pozostanie ważne.

  3. W przypadku elementów erase tylko iteratory wskazujące na te zostaną unieważnione; inne iteratory pozostaną ważne.

+0

Mam problemy z rozumieniem punktu 2. Czy możesz podać mi przykład? dziękuję – q0987

+1

@ q0987 Na przykład, jeśli uzyskano odwołanie do wartości przechowywanej w haszdzie, np. 'int & val = myMap [" hello "];', nawet jeśli wstawisz tyle elementów, ile potrzeba, aby wywołać ponowne przydzielenie, 'val' nadal będzie poprawnym odwołaniem do liczby całkowitej zapisanej dla ciągu' "hello" '. Tak samo jest, jeśli otrzymasz referencję z iteratora. Iterator może zostać później unieważniony, ale odniesienie do wartości pozostanie ważne. – jogojapan

+0

Sprawdź http://stackoverflow.com/questions/6438086/iterator-invalidation-rules Wstawianie dla wektora. wektor: wszystkie iteratory i odwołania przed punktem wstawienia pozostają nienaruszone, chyba że nowy rozmiar kontenera jest większy niż poprzednia pojemność (w tym przypadku wszystkie iteratory i odwołania są unieważniane) [23.2.4.3/1] – q0987

Powiązane problemy