1

可能重复:
如何从 std::map 中过滤项目?
std::list::erase 不起作用

我对 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.remove(3),如果mylist is list<int>。我怎样才能让它工作?

4

3 回答 3

2

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

it = ml.erase(it);
// 'it' now points at first element after the last deleted element
于 2013-01-21T15:28:55.673 回答
1

因为擦除使迭代器无效。它可能不再被使用,包括减量运算符。

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

于 2013-01-21T14:56:48.613 回答
1

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

现在,使用

ml.erase(it--);

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

但如果你这样做

ml.erase(it);
it--;

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

于 2013-01-21T15:20:47.330 回答