从标准::列表中删除/擦除

remove/erase from std::list

本文关键字:擦除 删除 列表 标准      更新时间:2023-10-16

可能的重复项:
如何从标准::地图中过滤项目?
标准::列表::擦除不起作用

我有一些关于删除,擦除的愚蠢问题 std::list.

我有一个定义为:

class CBase
{
public:
    CBase(int i): m(i)
    {};
    int m;
};

然后,我将其设置为:

list<CBase> ml;
CBase b1(1);
CBase b2(2);
CBase b3(3);
CBase b4(4);
ml.push_back(b1);
ml.push_back(b2);
ml.push_back(b3);
ml.push_back(b4);

我可以擦除 m==2 的项目;

for (list<CBase>::iterator it=ml.begin(); it!=ml.end(); ++it)
{
    if (it->m == 2)
    {
        ml.erase(it--);
    }
}
    // show what we have now:
for (list<CBase>::iterator it=ml.begin(); it!=ml.end(); it++)
{
    cout << it->m;
}

但如果我这样做:

for (list<CBase>::iterator it=ml.begin(); it!=ml.end(); it++)
{
    if (it->m == 2)
    {
        ml.erase(it);
        it--;
    }
}

会有例外。这是为什么呢?

如果我想删除 b3,

ml.remove(b3);

不会编译。我在网上找到的所有示例都使用list<int>,如果mylist is list<int>,调用mylist.remove(3)没有问题。我怎样才能让它工作?

您正在取消引用指向已擦除元素的迭代器。使用 erase() 成员函数的返回值:

it = ml.erase(it);
// 'it' now points at first element after the last deleted element

因为擦除会使迭代器失效。它可能不再使用,包括递减运算符。

编辑:至于删除,它会删除值等于您指定的元素。 std::list使用operator==进行比较,除非您定义了它,否则编译将失败。只需定义运算符,应该没问题。

erase之后,你传递给它的迭代器将是无效的。

现在,使用

ml.erase(it--);

您正在传递迭代器的副本erase并向后移动副本,以便它不再引用列表中的同一位置。
--发生在erase的副本准备好之后,但在实际调用erase之前
调用后,迭代器仍然有效,并且它比您删除的元素早一个位置。

但如果你这样做

ml.erase(it);
it--;

it 在调用后仍在尝试引用已删除的元素,当您尝试修改它时,您会收到异常,因为它无效。