C++映射/设置迭代器在使用多映射时出现不可增加的错误

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

本文关键字:映射 错误 可增加 设置 迭代器 C++      更新时间:2023-10-16

我遇到了与多映射相关的"map/set迭代器不可增加"错误。我试过在谷歌上搜索答案,但答案对我没有帮助。我认为问题是因为我代码的第一部分执行"akcja"命令,该命令可能(但不必)删除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->second->ryowanie()<<endl;"部分,以确认从多映射中删除任何元素后是否出现错误。如果有任何帮助,我将不胜感激

如果在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是一个值不能为null的指针,延迟擦除的一种简单形式是简单地将要擦除的元素的映射值设置为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 
        */
    }
  }
}