矢量迭代器在条件下擦除两个元素

Vector Iterator erase two elements on condition

本文关键字:两个 元素 擦除 迭代器 条件下      更新时间:2023-10-16

如果满足某些条件,我目前正试图从向量中删除2个元素。我可以成功地删除单个元素,而不会出现"矢量迭代器不可取消引用"错误,我知道问题是由同时删除两个元素引起的,这会扰乱迭代器,但我不确定同时删除多个元素的正确方法。

vector<SomeObj*> objs;
vector<SomeObj*>::iterator it = objs.begin();
while (it != objs.end())
{
    vector<SomeObj*>::iterator it2 = objs.begin();
    bool deleted = 0;
    while (it2 != objs.end())
    {
        if ((*it)->somecondition(**it2))
        {
            delete *it2;
            *it2 = NULL;
            it = objs.erase(it2);
            delete *it;
            *it = NULL;
            it = objs.erase(it); //Will error here due to invalidating the iterator
            deleted = 1;
            break;
        }
        ++it2;
    }
    if (!deleted)
        ++it;
}

问题是,对erase()的第一次调用很可能会使其他迭代器失效。请参阅这篇文章,快速总结在各种容器中无效的内容。我认为最简单的解决方案是首先遍历容器并标记要擦除的条目,但不擦除它们,然后在第二次扫描中只擦除标记的所有内容。出于性能原因,在第二次扫描中,您应该使用std::remove_if或使用反向迭代器。

如果要更改容器,使用嵌套迭代器是很棘手的。

我整理了一些示例代码,可以满足您的需求。我正在做的是通过将要删除的元素设置为nullptr来延迟删除,然后在循环中遇到这些元素时删除它们。

#include <iostream>
#include <vector>
class Example
{
public:
    Example(int size) : size(size) {}
    bool somecondition(const Example& other) const
    {
        return size == other.size;
    }
    int size;
};
int main()
{
    std::vector<Example*> vec;
    vec.push_back(new Example(1));
    vec.push_back(new Example(2));
    vec.push_back(new Example(3));
    vec.push_back(new Example(2));
    for (auto it1 = vec.begin(); it1 != vec.end();)
    {
        if (!*it1)
        {
            it1 = vec.erase(it1);
            continue;
        }
        for (auto it2 = vec.begin(); it2 != vec.end(); ++it2)
        {
            if (!*it2)
            {
                vec.erase(it2);
                // we need to start the outer loop again since we've invalidated its iterator
                it1 = vec.begin();
                break;
            }
            if (it1 != it2 && (*it1)->somecondition(**it2))
            {
                delete *it1;
                *it1 = nullptr;
                delete *it2;
                *it2 = nullptr;
                break;
            }
        }
        ++it1;
    }
    for (auto example : vec)
    {
        std::cout << example->size << std::endl;
    }
    return 0;
}