【问题标题】:strange iterator behavior in for loop in g++g ++中for循环中的奇怪迭代器行为
【发布时间】:2012-10-20 07:51:15
【问题描述】:

我得到这个奇怪的问题是代码 sn-p 工作正常。

std::multimap<long,int>::iterator dateItr = reconnQueueDates.begin();

while( dateItr!=reconnQueueDates.end()  ){
LOG_DEBUG("RUN comparision " <<cDateTime<< ", "<<dateItr->first);
if(dateItr->first <= cDateTime){
    long nextTimeout = -1;
   if( (nextTimeout = callReconnects(dateItr->second,dateItr->first))>-1){

        if(nextTimeout>0){
       reconnQueueDates.insert(std::pair<long , int>(nextTimeout, dateItr->second));
            }
            reconnQueueDates.erase(dateItr);
     LOG_DEBUG("modified the iterator ressetting");
     dateItr = reconnQueueDates.begin();
     LOG_DEBUG("resset iter");
   }//end of callreconnect if
}else{
 ++dateItr;
} //else for datetime check
 }//end of while

在此之前,我在循环中使用了带有 ++dateItr 的 for 循环,如下所示

 for( ;dateItr!=reconnQueueDates.end();++dateItr  ){
LOG_DEBUG("RUN comparision " <<cDateTime<< ", "<<dateItr->first);
if(dateItr->first <= cDateTime){
   long nextTimeout = -1;
   if( (nextTimeout = callReconnects(dateItr->second,dateItr->first))>-1){


            if(nextTimeout>0){
       reconnQueueDates.insert(std::pair<long , int>(nextTimeout, dateItr->second));       
             }
             reconnQueueDates.erase(dateItr);

        LOG_DEBUG("modified the iterator ressetting");
    dateItr = reconnQueueDates.begin();
    LOG_DEBUG("resset iter");
   }// callReconnect 
} // check datetime

 }// for loop

在调试时,我发现在循环内更改映射后,for 构造内的迭代器值仍在使用旧地址。

我正在使用 ubuntu 12.04 和 g++ 版本 4.6.3。在我看来,这是某种编译器错误或某种优化。

知道它可能是哪个标志或错误。

【问题讨论】:

  • 你必须展示你之前的完整循环(那个不工作的循环)。您在此处的正文与您在此处的(不完整的)for 不兼容。
  • 您的问题/问题到底是什么?这是否与 reconnQueueDates.insert()reconnQueueDates.erase() 调用之后的调用使用了无效的迭代器这一事实有关?
  • 代码中也存在一些逻辑错误。但我的问题是,为什么迭代器会进入无限循环。使用 for 循环时。虽然我正在使用 map.begin 更新迭代器的值。

标签: c++ stl


【解决方案1】:

reconnQueueDates.erase(dateItr); 之后,dateItr 中的迭代器无效,任何使用它都是未定义的行为。由于您的新旧 for 循环之后都使用它,因此您的新版本“有效”这一事实纯属偶然。

正确的做法是在擦除该元素之前首先提取您可能仍需要的所有数据(包括下一个迭代器的位置)。例如:

std::multimap<long,int>::iterator dateItr = reconnQueueDates.begin();

while( dateItr!=reconnQueueDates.end()  )
{
  LOG_DEBUG("RUN comparision " <<cDateTime<< ", "<<dateItr->first);
  if(dateItr->first <= cDateTime)
  {
    std::multimap<long,int>::iterator nextItr = dateItr;
    ++nextItr;
    long nextTimeout = -1;
    if( (nextTimeout = callReconnects(dateItr->second,dateItr->first))>-1)
    {
      std::pair<long , int> newentry = std::make_pair(nextTimeout, dateItr->second);
      reconnQueueDates.erase(dateItr);
      if(nextTimeout>0)
      {
        reconnQueueDates.insert(newentry);
      }
      LOG_DEBUG("modified the iterator resetting");
      nextItr = reconnQueueDates.begin();
      LOG_DEBUG("reset iter");
    }//end of callreconnect if
    dateItr = nextItr;
  }
  else
  {
    ++dateItr;
  } //else for datetime check
}//end of while

【讨论】:

  • 旁注:由于 C++11 std::multimap.erase 会返回一个迭代器,所以 "nextItr = reconnQueueDates.erase(dateItr);"节省一些开销。
猜你喜欢
  • 1970-01-01
  • 2016-02-16
  • 2014-03-15
  • 1970-01-01
  • 2019-02-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多