列表迭代器不可递增

发布于 2024-07-07 17:17:43 字数 576 浏览 4 评论 0原文

我有一个使用 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 调试器给我的信息。 有人可以向我解释一下问题是什么吗?

谢谢

I have an old project that was built using visual studio 2003 and I recompiled it with vs2005 recently. 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. Could somebody explain to me what the problem is?

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

抠脚大汉 2024-07-14 17:17:43

我会将您的循环重写为如下所示:

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

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

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.

败给现实 2024-07-14 17:17:43

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

如果要删除的项目是列表中的最后一项,则这显然无法正常工作。 我敢说即使在 VS2003 中它也无法正常工作,但 VS2005 会更好地提醒您。 :-)

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

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.

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. :-)

Remember, it's undefined behaviour to iterate past end(). Absolutely anything can happen, such as program crash, or (in this case) an error message.

血之狂魔 2024-07-14 17:17:43

我将删除几行代码来显示问题所在:

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

                iter++; // ***

        }
    }

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

一种解决方案是在执行第二个增量之前检查您是否处于 end() ,但在我看来,您正在尝试执行与我在 我不久前的问题与从容器(在这种情况下是地图)中过滤项目有关,但这同样适用于大多数 STL 容器)。

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).

在梵高的星空下 2024-07-14 17:17:43

根本原因是“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?
    }
   }

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

The root cause is "list.erase()" will change the iterator. The correct write for "for" loop:

   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.

倒数 2024-07-14 17:17:43

我相信克里斯是对的。 然而,另一个问题可能源于您分配给迭代器的事实。 – 列表迭代器是否保证可分配? 如果不看标准,我不这么认为,因为迭代器的 SGI 文档中没有提到可分配性。

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.

灯角 2024-07-14 17:17:43

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

我猜你是从 std::ist 继承的。 我必须说:继承以重用功能对我来说通常效果并不好。 但由于您也“继承”了该项目,因此没有什么可做的......

This is but a sidenote, but an important one.

I guess you inherit from a 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...

东风软 2024-07-14 17:17:43

如果您收到“列表迭代器不兼容”,可能是因为在“ReadyQueue::getInstance()->add(*iter);”内部 您正在更改 *iter 中的某些内容,这使得哈希算法返回的擦除值与插入期间的值不同。

If you getting "list iterator incompatible" it's probably because inside your "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.

流心雨 2024-07-14 17:17:43

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

免费函数 std::remove_if 可用于将列表分为 2 个匹配或不匹配谓词的元素(即arrivalTime==0)。 它返回分隔范围的迭代器。 然后,您可以调用 ReadyQueue::getInstance()->add(subrange_begin, subrange_end)(您确实有该重载,对吧?),然后删除子范围。

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

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 (i.e. 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.

Just a case where you can use STL algorithms instead of writing your own loops.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文