迭代时擦除set元素 [英] erase set element while iterating///

查看:61
本文介绍了迭代时擦除set元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不明白,为什么是运行时错误?迭代时擦除set元素.

I don't understand, why it is runtime error? Erase set element while iterating.

set<int> sset;
sset.insert(3);
sset.insert(5);
sset.insert(6);

for(auto s: sset){
    sset.erase(s);
}

推荐答案

因此,为了进一步解释,

So just to explain further,

您实际写的是:

for (set<int>::const_iterator i=sset.begin(), e=sset.end(); i != e; i++)
{
    auto s = *i;
    sset.erase(s);
}

因此,问题在于执行擦除时,内部迭代器 i 变得无效.尝试顺序删除许多容器中的内容通常是很痛苦的.

So the issue is that on doing the erase, the internal iterator i becomes invalidated. This is a general pain with trying to sequentially delete the content of many of the containers.

出于相同的原因,以下更传统的顺序删除代码也很糟糕,但也许更明显:

The following more traditional sequential delete code is also bad for the same reason, but perhaps more obviously:

for (set<int>::iterator i=sset.begin(), e=sset.end(); i != e; i++)
{
    sset.erase(i);
}

修复:

通常,在可能的情况下,更容易依赖整个容器的上下文交换销毁:

Generally, it is simpler to rely on context swap destruction of the whole container, when you can:

C++98: SsetType().swap(sset); 
C++11: sset = decltype<sset>();

您可以这样做:

sset.erase(sset.begin(), sset.end());

解决此问题的另一种方法是继续删除 begin(),直到集合为 empty()

Another way to fix this is to just keep deleting the begin() until the set is empty()

但是所有这些的问题是,您不能轻易地将它们扩展为有条件地擦除要遍历的集合中的成员.是的,也有用于条件擦除的助手,它们可以与lambda一起使用,因此它们可以承载状态,但是它们通常比滚动自己的循环难用.

But the problem with all of these is you can't easily extend them to conditionally erase members of a set you are iterating through. Yes, there are helpers for conditional erase as well, and they can be used with lambdas, so they can carry state, but they generally tend to be as hard to use as rolling your own loop.

自c ++ 11起,set :: erase(iterator)返回一个可以继续进行迭代的新迭代器,因此您可以编写:

Since c++11, set::erase(iterator) returns a new iterator which is safe to continue iterating with, so you can write:

for (set<int>::iterator i=sset.begin(), e=sset.end(); i != e; )
{
    i = sset.erase(i);
}

如果您正在执行一些条件测试,那么:

If you were performing some conditional test, then:

for (set<int>::iterator i=sset.begin(), e=sset.end(); i != e; )
{
    if ( ... condition ... )
        i = sset.erase(i);
    else
        i++;
}

之前,在c ++ 98中,您应该编写如下内容:

before, in c++98, you would have written something like:

for (set<int>::iterator i=sset.begin(), e=sset.end(); i != e; )
{
    auto j = i;
    j++;
    if ( ... condition ... )
        i = sset.erase(i);
    i = j;
}

作为练习,您可以将 j 的用法扩展到 for 语句中.但是,在C98中获得初始j ++会很棘手!

As an exercise, you can roll the use of j into the for statement. getting the initial j++ in C98 is tricky, though!

这篇关于迭代时擦除set元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆