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

发布于 2024-07-11 05:01:24 字数 571 浏览 5 评论 0原文

请考虑以下场景:


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 中等于什么?

谢谢...

Please consider the following scenario:


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

It seems to me that in VS2005, after the "erase", the iterator will be equal to end(), hence the crash while trying to increment it.
Are there really differences between compilers in the behavior presented here?
If so, what will the iterator after the "erase" equal to in UNIX/Linux?

Thanks...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

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

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::map 或 <代码>std::set。

Yes, if you erase an iterator, that iterator gets a so-called singular value, which means it doesn't belong to any container anymore. You can't increment, decrement or read it out/write to it anymore. The correct way to do that loop is:

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;
    }
}

For containers that could invalidate other iterators when you erase one iterator, erase returns the next valid iterator. Then you do it with

it = T2pS.erase(it)

That's how it works for std::vector and std::deque, but not for std::map or std::set.

请止步禁区 2024-07-18 05:01:24

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

T2pS.erase( it++ );

当然,如果您使用这种方法,您不会希望无条件地增加 it for 循环。

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

另一方面,看起来您在地图的“右侧”有一个原始指针,但地图似乎拥有所指向的对象。 在这种情况下,为什么不让地图右侧的东西成为某种智能指针,例如 std::tr1::shared_ptr?

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

After you call erase on an iterator into a std::map, it is invalidated. This means that you cannot use it. Attempting to use it (e.g. by incrementing it) is invalid and can cause anything to happen (including a crash). For a std::map, calling erase on an iterator does not invalidate any other iterator so (for example) after this call, (so long as it was not T2pS.end()), it will be valid:

T2pS.erase( it++ );

Of course, if you use this approach, you won't want to unconditionally increment it in the for loop.

For this example, though, why bother to erase in the for loop? Why not just call T2pS.clear() at the end of the loop.

On the other hand, it looks like you have a raw pointer 'on the right' of the map, but the map appears to own the pointed to object. In this case, why not make the thing on the right of the map some sort of smart pointer, such as std::tr1::shared_ptr?

[Incidentally, I don't see any template parameters to map. Have you typedef'ed a specific instantiation of std::map as map in the local namespace?]

德意的啸 2024-07-18 05:01:24

查看此内容

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

See this:

for (i = v.begin(); i != v.end(); ) {
  //...
  if (erase_required) {
      i = v.erase(i);
  } else {
      ++i;
  }
}
魔法少女 2024-07-18 05:01:24

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

I think if you modify the collection you invalidate your iterator. You can't rely on the behavior, as you found out.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文