在VS,UNIX / Linux中擦除STL迭代器后会发生什么?

时间:2009-01-11 16:33:42

标签: c++ linux visual-studio-2005 stl map

请考虑以下情况:


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

在我看来,在VS2005中,在“擦除”之后,迭代器将等于end(),因此在尝试增加它时崩溃。 在这里呈现的行为中,编译器之间是否存在真正的差异? 如果是这样,“擦除”之后的迭代器将在UNIX / Linux中等于什么?

...谢谢

4 个答案:

答案 0 :(得分:21)

是的,如果删除迭代器,那么迭代器会得到一个所谓的奇异值,这意味着它不再属于任何容器。你不能再增加,减少或读出它。执行该循环的正确方法是:

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::vectorstd::deque,但不适用于std::mapstd::set

答案 1 :(得分:4)

将迭代器上的erase调用std::map后,它将失效。这意味着您无法使用它。尝试使用它(例如通过递增)是无效的,可能导致任何事情发生(包括崩溃)。对于std::map,在迭代器上调用erase不会使此调用之后的任何其他迭代器失效(例如)(只要it不是T2pS.end()),它将是有效的:

T2pS.erase( it++ );

当然,如果您使用此方法,则不希望在for循环中无条件地增加it

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

另一方面,看起来你在地图的右边有一个原始指针,但地图似乎拥有指向的对象。在这种情况下,为什么不在地图的右边做一些智能指针,比如std :: tr1 :: shared_ptr?

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

答案 2 :(得分:0)

See this

for (i = v.begin(); i != v.end(); ) {
  //...
  if (erase_required) {
      i = v.erase(i);
  } else {
      ++i;
  }
}

答案 3 :(得分:0)

我认为如果修改集合,则会使迭代器失效。你发现,你不能依赖这种行为。