我有一个使用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调试器给我的。有人可以向我解释问题是什么吗?
由于
答案 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算法而不是编写自己的循环。