列表迭代器不可递增

时间:2008-10-13 08:07:42

标签: c++ list stl iterator

我有一个使用visual studio 2003构建的旧项目,最近我用vs2005重新编译了它。但是,在运行时,我收到以下错误:

列出迭代器不可递增

我将程序追溯到这个函数:

void InputQueue::update()
{
    list<PCB>::iterator iter;
    list<PCB>::iterator iterTemp;
    for(iter = begin(); iter != end(); iter++)
    {
        if(iter->arrivalTime == 0)
        {           
            ReadyQueue::getInstance()->add(*iter);
            iterTemp = iter;
            iter++;
            erase(iterTemp);
        }
    }
}

我不是C ++专家,这就是VS调试器给我的。有人可以向我解释问题是什么吗?

由于

8 个答案:

答案 0 :(得分:14)

我会重新编写你的循环,如下所示:

while (iter != end())
{
  if (iter->arrivalTime == 0)
  {
    ReadyQueue::getInstance()->add(*iter);
    iter = erase(iter);
  }
  else
  {
    ++iter;
  }
}

现在,您正在循环检查每个索引的列表。

答案 1 :(得分:9)

请注意,如果iter->arrivalTime == 0,那么列表迭代器会增加两次:在元素删除之前一次,在循环结束时再次增加。

如果要删除的项目是列表中的最后一项,则显然无法正常工作。我敢说它甚至在VS2003中都没有正常工作,但是VS2005会更好地提醒你。 : - )

请记住,迭代过去end()是未定义的行为。绝对可能发生任何事情,例如程序崩溃,或(在这种情况下)错误消息。

答案 2 :(得分:1)

我只是要删除几行代码来说明问题所在:

    for(iter = begin(); iter != end(); iter++) // ***
    {
        if(iter->arrivalTime == 0)
        {                       

                iter++; // ***

        }
    }

在标记为***的两行上,您正在递增迭代器。问题是,在两行中的第二行,您没有检查是否没有到达容器的末尾。实际上,如果你进入内循环,你会增加两次,但只检查你是否能够增加一次。

一个解决方案是在进行第二次增量之前检查你是否在end(),但在我看来,你正在尝试执行与我在my question a while ago中进行过滤相同的操作容器中的项目(在这种情况下为地图,但大多数STL容器都适用)。

答案 3 :(得分:1)

根本原因是“list.erase()”将改变迭代器。正确写入“for”循环:

   for (list<CMessage*>::iterator it=que.begin(); it!=que.end(); ++it)
   {
    if(m_type == (*it)->m_type)
    {
        delete *it;
        it=que.erase(it); //"list.erase()" will change the iterator!!!
        if(it==que.end()) break; //Check again!!!
        //still has side effect here. --it?
    }
   }

但它仍然有副作用,所以马克的解决方案将是最好的。

答案 4 :(得分:0)

我相信克里斯是对的。但是,另一个问题可能源于您分配给迭代器的事实。 - 列表迭代器是否可以保证可分配?在不查看标准的情况下,我不这么认为,因为在迭代器的SGI文档中没有提到可赋值性。

答案 5 :(得分:0)

这只是一个旁注,但却很重要。

我猜你是从std::ist<PCB>继承的。我必须说:继承重用功能对我来说并不常见。但既然你也“继承”了这个项目,那就没什么可做的......

答案 6 :(得分:0)

如果你得到“list iterator incompatible”,可能是因为你的“ReadyQueue :: getInstance() - &gt; add(* iter);”你正在改变* iter中的一些东西,使得哈希算法返回一个不同的值用于擦除,而不是插入过程中。

答案 7 :(得分:0)

我可以建议一个更简单的算法吗?

自由函数std::remove_if可用于将列表分区为2,与谓词匹配或不匹配的元素(即arrivalTime == 0)。它返回分隔范围的迭代器。然后你可以拨打ReadyQueue::getInstance()->add(subrange_begin, subrange_end) (你确实有那个超载,对吗?)然后删除子范围。

只是您可以使用STL算法而不是编写自己的循环。