azat
azat

Reputation: 3565

std::map::erase & iterators

I have some thing like this code:

map<int, string> m;

m[1] = "a";
m[2] = "b";
m[3] = "a";
m[4] = "a";
m[5] = "e";
m[6] = "f";
m[7] = "g";
m[8] = "h";
m[9] = "i";

for (it1 = src.begin(); it1 != src.end(); ++it1) {

    for (it2 = it1; it2 != src.end(); ++it2) {
        if (it2 == it1) {
            continue;
        }

        if (it2->second == it1->second) {
            fprintf(stderr, "%u\n", it2->first);
            src.erase(it2);
        }
    }
}

I use map, because the elements is not always in this order (1, 2 ...)
So here is the question

In some cases of map values, this code print this

2
3
4
6
7
8
9
5

How it is possible (skipping 5), if map sort by container in order 1, 2 ... and so on ?

Upvotes: 1

Views: 546

Answers (1)

Kerrek SB
Kerrek SB

Reputation: 477110

Your erase loop is off. The typical idiom is this:

for(std::map<K,V>::const_iterator it = v.begin(); it != v.end() /* not hoisted! */; /* no increment */ )
{
  // do something
  if (suitable_condition)
  {
    v.erase(it++);
  }
  else
  {
    ++it;
  }
}

Your code erroneously performs an increment on an invalid iterator (namely it2 after the erase), which is undefined behaviour.

(For certain other container types, erase returns an iterator to the next valid element, so in those cases you would say it = v.erase(it); but the details of the best erasing pattern depend on the concrete container type.)

Upvotes: 12

Related Questions