简体   繁体   中英

C++ map/set iterator not incrementable error while using multimap

I have a problem with the "map/set iterator not incrementable" error related to my multimap. I have tried googling for answers, but the answers did not help me. I'm assuming that the problem is because first part of my code executes the "akcja" command, which may (but doesn't have to) delete one of the components of multimap:

    while ((c = getch()) != 27)
    {
        if (c == 'n')
        {
            typedef multimap<int, Organizm*>::iterator iterator;
            for (int i = 10; i>= 0; i--)
            {
                std::pair<iterator, iterator> iterpair = kolejnoscRuchu.equal_range(i);
                iterator it = iterpair.first;

                for (; it != iterpair.second; ++it)
                {
                    if(it->second->inicjatywa !=0)
                    {
                    it->second->akcja();
                    }
                }
            }

}

If certain conditions are met the akcja() will trigger the command which removes the element:

void Swiat::usunOrganizm(Organizm *organizm)
{
    this->organizmy[organizm->pozycja.x][organizm->pozycja.y] = NULL;

    typedef multimap<int, Organizm*>::iterator iterator;
    std::pair<iterator, iterator> iterpair2 = this->kolejnoscRuchu.equal_range(organizm->inicjatywa);

    iterator it2 = iterpair2.first;
    for (; it2 != iterpair2.second; ++it2) 
    {
        if (it2->second == organizm) 
        {
            cout << "usuwam " << it2->second->rysowanie() << endl;
            kolejnoscRuchu.erase(it2);
            delete organizm;
            break;
        }
    }
}

I've added a "cout << "usuwam " << it2->second->rysowanie() << endl;" part to confirm if the error occurs after removing any elements from my multimap. I would appreciate any help

If you erase the element at it2 , then you can no longer use it2 . Incrementing it will no longer be possible.

You can easily write an iteration loop which tolerates the erasure of the loop control itself:

iterator it = iterpair2.first;
while (it != iterpair.second)
{
    iterator next_it = it;
    ++next_it;
    /* it's possible for it to be deleted here */
    it = next_it;
}

However, the above will fail if next_it is erased in the loop body. So if you wanted to be more general, you'd need an explicit comparison:

while (it != iterpair.second)
{
    iterator next_it = it;
    ++next_it;
    /* ... */
    if (some_condition)
    {
        /* Need to erase it_to_erase */
        if (it_to_erase == next_it) ++next_it;
        theMap.erase(it_to_erase);
    }
    /* ... */
    it = next_it;
}

Even that requires that the code which iterates is also the code which erases the element. If the erasing code is unrelated (say, because it is in a function called in the iteration), then there is really no solution which allows for immediate erasure.

So in that case, you'd need to implement some form of deferred erasure. In the particular case presented in the OP, where the map's mapped_type is a pointer whose value cannot be null, an easy form of deferred erasure is to simply set the mapped value of the element to be erased to 0.

In the simple deferred erasure scheme below, I assume that the outer loop is itself free to erase elements; that is, it is not in a function called during an iteration. I use some C+11 features for simplicity.

/* Outer loop */

for (auto it = myMap.begin(), end = myMap.end();; ++i) {
  /* Erase any previously marked elements */
  while (it != end && !it->second) it = myMap.erase(it);
  if (it == end) break;

  /* Do something with this element */
  /* ... */
  /* This function might "delete" arbitrary elements. See below */
  secondProcess(myMap);
  /* At this point, "it" might not be valid, so you would need to
     check before trying to use it.
   */
}

And here's the inner function:

void secondProcess(MapType& myMap) {
  /* ... */
  for (auto it2 = myMap.begin(), end = myMap.end(); it2 != end; ++it2) {
    if (it2->second) { /* Make sure the element is not already marked */
      /* ... */

      /* Here we've decided to erase the element at "it2"
       * The delete comes from the code in OP; it is only OK if the
       * mapped value is the only pointer to the object it points to.
       */
         delete it2->second;
         it2->second = 0;
       /* Since we don't actually erase it2, no other adjustment
        * is needed 
        */
    }
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM