代码之家  ›  专栏  ›  技术社区  ›  Gal Goldman

在VS、UNIX/Linux中删除STL迭代器后会发生什么情况?

  •  7
  • Gal Goldman  · 技术社区  · 16 年前

    请考虑以下情况:

    
    map(T,S*) & GetMap(); //Forward decleration
    
    map(T, S*) T2pS = GetMap();
    
    for(map(T, S*)::iterator it = T2pS.begin(); it != T2pS.end(); ++it)
    {
        if(it->second != NULL)
        {
            delete it->second;
            it->second = NULL;
        }
        T2pS.erase(it);
        //In VS2005, after the erase, we will crash on the ++it of the for loop.
        //In UNIX, Linux, this doesn't crash.
    }//for
    

    在这里介绍的行为中,编译器之间真的存在差异吗? 如果是这样,在UNIX/Linux中,“擦除”之后的迭代器将等于什么?

    4 回复  |  直到 16 年前
        1
  •  22
  •   Johannes Schaub - litb    16 年前

    是的,如果你删除一个迭代器,这个迭代器会得到一个所谓的 ,这意味着它不再属于任何容器。你不能再递增、递减或读/写了。执行该循环的正确方法是:

    for(map<T, S*>::iterator it = T2pS.begin(); it != T2pS.end(); T2pS.erase(it++)) {
        // wilhelmtell in the comments is right: no need to check for NULL. 
        // delete of a NULL pointer is a no-op.
        if(it->second != NULL) {
            delete it->second;
            it->second = NULL;
        }
    }
    

    erase 返回下一个有效迭代器。那你就和我一起做吧

    it = T2pS.erase(it)
    

    std::vector std::deque ,但不是为 std::map std::set

        2
  •  5
  •   CB Bailey    16 年前

    erase 将迭代器转换为 std::map ,则无效。这意味着你不能使用它。试图使用它(例如,通过增加它)是无效的,可能会导致任何事情发生(包括崩溃)。暂时 擦除 在迭代器上,不会使任何其他迭代器so(例如)在此调用之后失效(只要 it T2pS.end() ),有效期为:

    T2pS.erase( it++ );
    

    当然,如果使用这种方法,您不会希望无条件地增加 信息技术

    但是,对于这个例子,为什么还要费心在For循环中擦除呢?为什么不在循环结束时调用T2pS.clear()。

    [顺便说一句,我没有看到任何模板参数 map . 您是否键入了的特定实例 地图 在本地命名空间中?]

        3
  •  0
  •   orip    16 年前

    See this

    for (i = v.begin(); i != v.end(); ) {
      //...
      if (erase_required) {
          i = v.erase(i);
      } else {
          ++i;
      }
    }
    
        4
  •  0
  •   Jonathan Adelson    16 年前

    我认为如果修改集合,就会使迭代器无效。正如你发现的那样,你不能依赖这种行为。