美文网首页
在VS,UNIX/Linux中删除STL迭代器后会发生什么

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

作者: 东东东东东东丶 | 来源:发表于2018-07-02 19:37 被阅读0次

原文:What happens to an STL iterator after erasing it in VS, UNIX/Linux?

翻译:

请考虑下面的脚本:

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 erase迭代器之后会等于end(),所以当尝试递增迭代器的时候会崩溃。真的会根据不同的编译期会产生不同的行为吗?如果是这样的话,在UNIX/Linux上,erase迭代器之后会发生什么呢?


Answers1:

是的,如果你 erase一个迭代器,它会得到一个叫做  singular的值,这意味着这个迭代器不再属于任何容器,你不能增加它、减少它或者读出/写入它。正确的循环代码应该是下面这个样子的:

for(map::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。


Answers2:

在 std::map的一个迭代器上调用 erase之后,它是无效的。这意味着你不能在使用它。尝试调用它(包括增加它)是无效的并且可能导致任何事情的发生(包括崩溃)。对于 std::map,调用 erase之后不会使任何其他迭代器失效,(只要迭代器不是 end())它就是有效的:

T2pS.erase( it++ );

当然,如果你正确的使用它,你不会想要在循环中无条件增加迭代器。

但是对于这个例子,为什么要在循环中删除它呢?为什么不在循环结尾调用 T2pS.clear()呢。

另一方面,你看起来想要 map的原生 second指针,但是 map似乎拥有指向的对象。在这种情况下,为什么不让 map的 second拥有智能指针呢,比如:std::tr1::shared_ptr。

【顺便说一句,我没有看到任何 map的模板参数。你是否在本地命名空间中使用 std::map作为 map的 typedef】


Answers3:

看这里

for (i = v.begin(); i != v.end(); ) {

  //...

  if (erase_required) {

      i = v.erase(i);

  } else {

      ++i;

  }

}


Answers4:

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

相关文章

网友评论

      本文标题:在VS,UNIX/Linux中删除STL迭代器后会发生什么

      本文链接:https://www.haomeiwen.com/subject/wllzyftx.html