【问题标题】:list iterator not incrementable列表迭代器不可递增
【发布时间】:2010-09-16 20:29:45
【问题描述】:

我有一个使用 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 调试器给我的。谁能给我解释一下问题出在哪里?

谢谢

【问题讨论】:

    标签: c++ list stl iterator


    【解决方案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?
        }
       }
    

    但是还是有副作用的,所以最好用 Mark 的 while 解决方案。

    【讨论】:

      【解决方案2】:

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

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

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

      【讨论】:

      • 你没有在 if 的第一部分增加迭代器
      • 我是 - iter = 擦除(iter)。擦除函数在刚刚删除的迭代器之后返回新的迭代器。
      • 哦,对了,别管我了。这不适用于某些类型的容器,请注意
      • 没错,但 OP 提到他正在使用列表(确实具有擦除功能)。
      【解决方案3】:

      我可以推荐一个更简单的算法吗?

      免费函数std::remove_if 可用于将列表划分为 2 个匹配或不匹配谓词的元素(即到达时间==0)。它返回分隔范围的迭代器。然后你可以调用ReadyQueue::getInstance()-&gt;add(subrange_begin, subrange_end)(你确实有过载,对吗?)然后删除子范围。

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

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          【解决方案5】:

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

          我猜你继承自 std::ist&lt;PCB&gt;。我必须说:继承以重用功能对我来说并不是很好。但是由于您也在“继承”该项目,因此没有什么可做的......

          【讨论】:

          • 实现继承虽然不理想,但如果它只是私有继承,则可以原谅。 :-)
          【解决方案6】:

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

          【讨论】:

          【解决方案7】:

          我将省略几行代码以显示问题所在:

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

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

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

          【讨论】:

            【解决方案8】:

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

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

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

            【讨论】:

              猜你喜欢
              • 2011-09-04
              • 1970-01-01
              • 1970-01-01
              • 2023-03-03
              • 2013-03-23
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多