Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this proper behavior? std::map iterator invalidation

#include <iostream>
#include <map>

int main(int argc, char** argv)
{
  std::map<int, int> map;
  map.emplace(1, 1);
  auto reverse_iter = map.rbegin();
  std::cout << reverse_iter->first << ", " << reverse_iter->second << std::endl;
  map.emplace(2, 2);
  std::cout << reverse_iter->first << ", " << reverse_iter->second << std::endl;

  return 0;
}

This prints out:

1, 1
2, 2

Is this really what's supposed to happen, according to the standard? I'm not touching reverse_iter but the value it's pointing to is changing. I thought iterators in std::map were supposed to be safe against insertion. Yet it seems to be deciding that reverse_iter is not to stay pointing to the value I told it to, rather to "whatever happens to be at the end of the map at this point in time".

Update: further info, in case it matters: this doesn't seem to happen with forward iterators (in any situation I can seem to find), and my gcc version is 5.1.1-4.

like image 722
KarenRei Avatar asked Nov 23 '15 21:11

KarenRei


People also ask

Does map insert invalidate iterator?

Set, map, multiset, multimapOnly iterators and references to the erased elements are invalidated.

How can we avoid iterator invalidation?

You could avoid moving elements of the container by maintaining a free-list (see http://www.memorymanagement.org/glossary/f.html#free.list). To avoid invalidation of references to elements you can use a std::deque if you do not insert or erase in the middle. To avoid invalidation of iterators you can use a std::list.

What is iterator invalidation in C++?

What is Iterator Invalidation? An Iterator becomes invalidate when the container it points to changes its shape internally i.e. move elements from one location to another and the initial iterator still points to old invalid location.

What is the complexity of std :: map :: insert () method?

Time complexity: k*log(n) where n is size of map, k is no. of elements inserted.


2 Answers

According to the C++ Standard (23.2.4 Associative containers)

9 The insert and emplace members shall not affect the validity of iterators and references to the container, and the erase members shall invalidate only iterators and references to the erased elements.

On the other hand (24.5.1 Reverse iterators)

1 Class template reverse_iterator is an iterator adaptor that iterates from the end of the sequence defined by its underlying iterator to the beginning of that sequence.

Though in the last quote there is said about class std::reverse_iterator the same is valid for reverse iterators of standard containers.

According to Table 97 — Reversible container requirements

rbegin() corresponds to reverse_iterator(end())

So in your example the reverse iterator still corresponds to end(). `

like image 170
Vlad from Moscow Avatar answered Sep 28 '22 06:09

Vlad from Moscow


As quoted here http://en.cppreference.com/w/cpp/container/map/rbegin

Reverse iterator stores an iterator to the next element than the one it actually refers to

the side effect would be that if you insert something before that iterator (incliding end()) you will see that new value when you dereference that reverse iterator. I do not think that reverse iterator is invalidated in this case.

like image 34
Slava Avatar answered Sep 28 '22 06:09

Slava