简体   繁体   English

矢量迭代器擦除条件上的两个元素

[英]Vector Iterator erase two elements on condition

I'm currently trying to delete 2 elements from a vector if some condition is met. 我正在尝试从某个向量中删除2个元素,如果满足某些条件的话。 I can successfully remove a single element without the "vector iterator not dereferencable" error occuring, I know the problem is been caused by removing two elements at once which messes up with the Iterators but am unsure as to the correct way of removing more than one element at once. 我可以成功删除单个元素而不会出现“矢量迭代器不可解除错误”错误,我知道这个问题是由于同时删除了两个元素引起的,这些元素与迭代器混淆但不确定删除多个元素的正确方法元素一下子。

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

The problem is that the first call to erase() might very well invalidate the other iterator. 问题是第一次调用erase()可能会使另一个迭代器无效。 See this post for a quick summary of what gets invalidated when in various containers. 有关在各种容器中失效的内容的快速摘要,请参阅此文章 I'd say the simplest solution is to first traverse the container and mark the entries to be erased but do not erase them, and then in a second scan just erase everything that was marked. 我想说最简单的解决方案是首先遍历容器并标记要删除的条目,但不要删除它们,然后在第二次扫描中擦除所有标记的内容。 For performance reasons in this second scan you should either use std::remove_if or use reverse iterator. 出于性能原因,在第二次扫描中,您应该使用std :: remove_if或使用反向迭代器。

Working with nested iterators is tricky if you are mutating the container. 如果要改变容器,使用嵌套迭代器是很棘手的。

I've put together some sample code that does what you are wanting. 我已经整理了一些样本代码,可以满足您的需求。 What I'm doing is delaying the removal by setting the elements to be removed to nullptr and then removing those as we encounter them in the loops. 我正在做的是通过将要删除的元素设置为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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM