c++ - 迭代时删除集合元素///

标签 c++

我不明白,为什么是运行时错误? 迭代时删除集合元素。

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

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

最佳答案

所以只是进一步解释,

你实际上写的是:

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

修复:

通常,依赖整个容器的上下文交换销毁会更简单,当您可以:

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++ 是很棘手的!

关于c++ - 迭代时删除集合元素///,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51208537/

相关文章:

c++ - 列出所有物理驱动器 (Windows)

c++ - Emacs + C/C++ + Doxygen : Alternative to doxymacs? 使用 yasnippet?

c++ - 使用 2 个线程的代码运行速度比使用 1 个线程慢 6 倍

c++ - 如何比较 vector 和数组?

c++ - 如何让Halide使用滑动窗口优化?

c++ - 从 lambda 表达式中抛出异常,坏习惯?

c++ - Mac OSX 上的 c/c++ clang 链接错误 - webkitgtk

c++ - 可以仅使用 std::sort() 将零移动到数组的末尾吗?

c++ - 个别动态分配的极端内存使用

c++ - 如何在 C++ 中进行内联汇编 (Visual Studio 2010)