11

Reference http://www.careercup.com/question?id=17188673 by chetan.j9

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);      
}

Question> Can we store the iterator of unordered_map for later retrieval? Based on my understanding, the iterator will be invalidated after the insertion or deletion of an element.

Thank you

q0987
  • 31,246
  • 61
  • 222
  • 356
  • 3
    A nice reference for iterator invalidation for all containers is http://stackoverflow.com/questions/6438086/iterator-invalidation-rules – JRG May 28 '13 at 02:07

2 Answers2

21

@syam's answer is correct (+1), but I think it's useful to quote from the only authoritative source, the C++11 Standard:

(§23.2.5/13) The insert and emplace members shall not affect the validity of references to container elements, but may invalidate all iterators to the container. The erase members shall invalidate only iterators and references to the erased elements.

(§23.2.5/14) The insert and emplace members shall not affect the validity of iterators if (N+n) < z * B, where N is the number of elements in the container prior to the insert operation, n is the number of elements inserted, B is the container’s bucket count, and z is the container’s maximum load factor.

(To put this in context: §23.2.5 is the section on unordered associative containers, so it applies to std::unordered_set, std::unordered_map, std::unordered_multiset and std::unordered_multimap.) This means:

  1. If you want to insert n elements into an unordered_map called hash, you can check whether

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

    is true. If it is false, all iterators will be invalidated during the insert. If true, iterators will remain valid.

  2. Even if iterators are invalidated in this operation, references to the elements themselves will remain valid.

  3. If you erase elements, only iterators pointing to those will be invalidated; other iterators will remain valid.

Community
  • 1
  • 1
jogojapan
  • 63,098
  • 9
  • 87
  • 125
  • I have problems to understand point 2. Can you give me an example? thank you – q0987 May 30 '13 at 14:39
  • 1
    @q0987 For example, if you obtained a reference to a value stored in the hash, e.g. `int &val = myMap["hello"];`, then even if you insert as many elements as necessary to trigger a re-allocation, `val` will still be a valid reference to the integer stored for the string `"hello"`. The same is true if you get the reference from an iterator. The iterator may be invalidated later, but the reference to a value will remain valid. – jogojapan May 30 '13 at 14:45
  • Check http://stackoverflow.com/questions/6438086/iterator-invalidation-rules Insertion for vector. vector: all iterators and references before the point of insertion are unaffected, unless the new container size is greater than the previous capacity (in which case all iterators and references are invalidated) [23.2.4.3/1] – q0987 May 31 '13 at 18:43
  • 2
    @q0987 I don't know what you are trying to tell me. But my answer referred to `std::unordered_map`, not `std::vector` because that's what your question is about. – jogojapan Jun 01 '13 at 01:22
  • Great answer. I would like to understand how it is possible to maintain the validity of the references after a rehash. Where could I read something about this? – Gonzalo Solera Jul 25 '18 at 21:25
  • Never mind, I just saw this question: https://stackoverflow.com/questions/11337494/c-stl-unordered-map-implementation-reference-validity – Gonzalo Solera Jul 26 '18 at 14:12
6

Insertion of an item invalidates all iterators only if a rehashing occurs (ie. if the new number of elements is greater than or equal to max_load_factor()*bucket_count()). Otherwise no iterators are invalidated.

Removal of an item only invalidates the iterators to the removed element(s) not to other unrelated elements.

Source: std::unordered_map::insert and std::unordered_map::erase.

Of course these rules apply only to std::unordered_map. Other containers may have different invalidation rules, it's up to you to look it up in the documentation.

syam
  • 13,907
  • 3
  • 36
  • 64
  • Since we don't know when the invalidation happens, the implement of `insert` is NOT correct. Right? – q0987 May 27 '13 at 23:48
  • @q0987 We actually know when the invalidation happens (the rule is quite clear). If you know the maximum number of items in advance then you can just [`reserve`](http://en.cppreference.com/w/cpp/container/unordered_map/reserve) beforehand and then you can store iterators safely even if you insert, as long as you don't go over that reserved maximum. But of course if you want to insert an unknown number of items that's a whole other story and storing iterators would indeed be a bad idea while you're still inserting items. – syam May 27 '13 at 23:57
  • 2
    Strictly speaking, the condition for rehashing is that the number of new elements is greater than _or equal to_ the formula you've given (or, since we are talking floating point numbers, better use less-than and the negation of the statement). – jogojapan May 28 '13 at 01:26
  • 1
    @jogojapan: Thanks for the precision, I've corrected it in my answer. Looks like cppreference.com has a small mistake, I'd edit it but those templates they use are a mess, I don't want to break anything. +1 for you quoting the standard. – syam May 28 '13 at 01:38
  • 2
    @jogojapan and syam: Thanks for noticing that documentation bug -- I've updated http://en.cppreference.com/w/cpp/container/unordered_map/insert. – Nate Kohl May 28 '13 at 01:55
  • @NateKohl I keep forgetting how easy it is to edit cppreference. I've created an account for myself, too, now. Thanks again. – jogojapan May 28 '13 at 02:07