所以只是进一步解释一下,
您有效编写的内容是:
for (set<int>::const_iterator i=sset.begin(), e=sset.end(); i != e; i++)
{
auto s = *i;
sset.erase(s);
}
所以问题是在进行擦除时,内部迭代器i
变得无效。尝试按顺序删除许多容器的内容时,这是一个普遍的痛苦。
由于同样的原因,以下更传统的顺序删除代码也很糟糕,但也许更明显:
for (set<int>::iterator i=sset.begin(), e=sset.end(); i != e; i++)
{
sset.erase(i);
}
Fixes:
一般来说,当您可以时,依靠整个容器的上下文交换销毁会更简单:
C++98: SsetType().swap(sset);
C++11: sset = decltype<sset>();
你可以这样做:
sset.erase(sset.begin(), sset.end());
解决此问题的另一种方法是继续删除begin()
直到集合为empty()
但所有这些的问题是您无法轻松地扩展它们以有条件地删除您正在迭代的集合中的成员。是的,还有条件擦除的帮助程序,它们可以与 lambda 一起使用,因此它们可以携带状态,但它们通常与滚动您自己的循环一样难以使用。
从 c++11 开始,set::erase(iterator) 返回一个新的迭代器,可以安全地继续迭代,因此您可以编写:
for (set<int>::iterator i=sset.begin(), e=sset.end(); i != e; )
{
i = sset.erase(i);
}
如果您正在执行一些条件测试,那么:
for (set<int>::iterator i=sset.begin(), e=sset.end(); i != e; )
{
if ( ... condition ... )
i = sset.erase(i);
else
i++;
}
以前,在 c++98 中,您可能会编写如下内容:
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++ 是很棘手的!