2015-12-09 3 views
0

У меня проблема с ошибкой «map/set iterator not incrementable», связанной с моим мультимапом. Я пробовал искать ответы, но ответы мне не помогли. Я предполагаю, что проблема в том, что первая часть моего кода выполняет «Akcja» команду, которая может (но не обязана) удалить один из компонентов Multimap:C++ map/set iterator not incrementable error при использовании 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(); 
        } 
       } 
      } 

}

Если определенные условия выполнены в Akcja() вызовет команду, которая удаляет элемент:

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

Я добавил «COUT < < "usuwam" < < it2-> второго> rysowanie() < < endl; " чтобы подтвердить, возникает ли ошибка после удаления каких-либо элементов из моего мультимапа. Буду признателен за любую помощь

ответ

1

Если вы удалите элемент по адресу it2, вы больше не сможете использовать it2. Увеличение его уже невозможно.

Вы можете легко написать цикл итерации, который переносит стирания самого управления с обратной связью:

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

Тем не менее, выше, будет ошибкой, если next_it стирается в теле цикла. Так что если вы хотите быть более общим, вам потребуется явное сравнение:

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

Даже то, что требует, чтобы код, который перебирает также код, который удаляет элемент. Если код стирания не связан (скажем, потому что он находится в функции, называемой итерацией), то на самом деле нет решения, которое позволяет немедленно стирать.

Так что в этом случае вам необходимо реализовать некоторую форму отложенного стирания. В конкретном случае, представленном в OP, где mapped_type - это указатель, значение которого не может быть нулевым, простая форма отложенного стирания заключается в простом преобразовании отображаемого значения стираемого элемента в 0.

В простая схема отложенного стирания ниже, я предполагаю, что внешний цикл сам по себе свободен для стирания элементов; то есть, это не функция, называемая во время итерации. Для простоты я использую некоторые функции C + 11.

/* 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. 
    */ 
} 

А вот внутренняя функция:

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 
     */ 
    } 
    } 
} 
+0

Спасибо, но я не уверен, если это решение будет всегда помогать мне. В основном в моем примере у меня есть 2 итератора, потому что мой мультимап - это контейнер организмов с их соответствующими инициативами со значениями от 0 до 10. Когда организм движется, он может сражаться с другим организмом, и если произойдет драка, один из них умрет - отсюда и второй итератор. Ваше решение позволяет мне повторять второй цикл, но что, если я удалю первый итератор во время функции «usunOrganizm»? –

+0

@LKaniewski: ОК, добавлено другое возможное решение. – rici