简体   繁体   English

列表迭代器不可递增

[英]list iterator not incrementable

I have an old project that was built using visual studio 2003 and I recompiled it with vs2005 recently. 我有一个使用visual studio 2003构建的旧项目,最近我用vs2005重新编译了它。 However, during runtime, I get the following error: 但是,在运行时,我收到以下错误:

list iterator not incrementable 列表迭代器不可递增

I traced the program to this function: 我跟踪程序到这个函数:

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

I'm not a C++ expert and this is as far as the VS debugger got me. 我不是C ++专家,这就是VS调试器给我的。 Could somebody explain to me what the problem is? 有人可以向我解释问题是什么吗?

Thanks 谢谢

I would re-write your loop to be like the following: 我会重新编写你的循环,如下所示:

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

Now you are correctly looping through the list checking every index. 现在,您正在循环检查每个索引的列表。

Notice that if iter->arrivalTime == 0 , then the list iterator gets incremented twice: once before element removal, and once again at the end of the loop. 请注意,如果iter->arrivalTime == 0 ,则列表迭代器会增加两次:在元素删除之前增加一次,在循环结束时再次增加。

If the item to be removed is the last item in the list, this will obviously not work correctly. 如果要删除的项目是列表中的最后一项,则显然无法正常工作。 I dare say that it never did work correctly even in VS2003, but VS2005 alerts you about it better. 我敢说它甚至在VS2003中都没有正常工作,但是VS2005会更好地提醒你。 :-) :-)

Remember, it's undefined behaviour to iterate past end() . 请记住,迭代到end()是未定义的行为。 Absolutely anything can happen, such as program crash, or (in this case) an error message. 绝对可能发生任何事情,例如程序崩溃,或(在这种情况下)错误消息。

I'm just going to elide a few lines of your code to show where the problem lies: 我只是要删除几行代码来说明问题所在:

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

                iter++; // ***

        }
    }

On the two lines marked ***, you are incrementing the iterator. 在标记为***的两行上,您正在递增迭代器。 The problem is that on the second of the two lines, you aren't checking to see that you haven't gone to the end of the container. 问题是,在两行中的第二行,您没有检查是否没有到达容器的末尾。 Effectively, if you get into the inner loop, you are incrementing twice, but only checking if you are able to increment once. 实际上,如果你进入内部循环,你会增加两次,但只检查你是否能够增加一次。

One solution is to check whether you are at end() before doing the second increment, but it looks to me like you are trying to preform the same operation as I was in my question a while ago to do with filtering items from a container (a map in that case, but the same applies for most STL containers). 一个解决方案是在执行第二次增量之前检查你是否在end() ,但它看起来像你试图在前面的问题中执行与我在容器中过滤项目时相同的操作(在这种情况下的地图,但同样适用于大多数STL容器)。

The root cause is "list.erase()" will change the iterator. 根本原因是“list.erase()”将改变迭代器。 The correct write for "for" loop: 正确写入“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?
    }
   }

But it still has side effect, so Mark's while solution will be the best. 但它仍然有副作用,因此Mark的解决方案将是最好的。

I beliebe Chris is right. 我相信克里斯是对的。 However, another problem might stem from the fact that you assign to the iterator. 但是,另一个问题可能源于您分配给迭代器的事实。 – Are list iterators guaranteed to be assignable? - 列表迭代器是否可以保证可分配? Without looking at the standard, I don't think so because assignability is nowhere mentioned in the SGI documentation of iterators. 在不查看标准的情况下,我不这么认为,因为在迭代器的SGI文档中没有提到可赋值性。

This is but a sidenote, but an important one. 这只是一个旁注,但却很重要。

I guess you inherit from a std::ist<PCB> . 我猜你是从std::ist<PCB>继承的。 I must say: inheriting to reuse functionality hasn't often turned out well for me. 我必须说:继承重用功能对我来说并不常见。 But since you're also 'inheriting' the project, there's nothing much to do about it... 但既然你也在“继承”这个项目,那就没什么可做的了......

If you getting "list iterator incompatible" it's probably because inside your "ReadyQueue::getInstance()->add(*iter);" 如果你得到“list iterator incompatible”,那可能是因为你的“ReadyQueue :: getInstance() - > add(* iter);” you are changing something in *iter that is making the hash algorithm returns a different value for erase than it did during the insert. 你正在改变* iter中的一些东西,使得哈希算法返回一个不同的值,用于擦除,而不是插入过程中。

May I suggest a simpler algorithm? 我可以建议一个更简单的算法吗?

The free function std::remove_if can be used to partition your list in 2, elements that match or don't match the predicate (ie arrivalTime==0). 自由函数std::remove_if可用于将列表分区为2,与谓词匹配或不匹配的元素(即arrivalTime == 0)。 It returns the iterator seperating the ranges. 它返回分隔范围的迭代器。 You can then call ReadyQueue::getInstance()->add(subrange_begin, subrange_end) (you do have that overload, right?) and erase the subrange afterwards. 然后你可以调用ReadyQueue::getInstance()->add(subrange_begin, subrange_end) (你确实有那个重载,对吗?)然后擦除子范围。

Just a case where you can use STL algorithms instead of writing your own loops. 只是您可以使用STL算法而不是编写自己的循环的情况。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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