如何在给定迭代器列表的情况下从向量中擦除元素?

时间:2018-01-24 01:48:59

标签: c++ vector c++14

我有一个int的向量,以及一个包含指向向量的迭代器作为值的映射。我需要从地图中删除键,以及值指向的向量元素。我的代码看起来很简单:

using RenderData = int;
using Element = std::string;

struct Ref {
    std::vector<RenderData>::iterator ref;
    std::function<int()> update;
    bool should_remove;
};

int main() {
    std::vector<RenderData> ints{1, 2, 3, 4, 5, 6, 7, 8, 9};
    std::unordered_map<Element, Ref> elements;

    // Here, I need to remove some elements, and their associated number
}

我实施了一个erase_if函数,看起来像this one

所以我的初始代码看起来像那样:

erase_if(elements, [&](auto&& element) {
    if (element.second.should_remove) {
        ints.erase(element.second.ref);
        return true;
    }

    return false;
});

显然没有用。擦除元素使其他迭代器指向错误的对象,在某些情况下超出绑定。所以我试过了:

std::vector<std::vector<RenderData>::iterator> to_remove;

erase_if(elements, [&](auto&& element) {
    // condition based on the string content
    if (element.second.should_remove) {
        to_remove.emplace_back(element.second.ref);
        return true;
    }

    return false;
});

// Sort in descending order
std::sort(to_remove.begin(), to_remove.end(), std::greater<>{});

// stuff

for (auto&& it : to_remove) {
    ints.erase(it); // nothing can go wrong right?
}

而且,有时我最终会删除错误的元素。

给定存储在某个map中的迭代器,我可以从向量中删除迭代器指向的元素吗?

更新

似乎在最后一个片段中我交换了向量中的一些元素,使得删除了错误的元素。现在它似乎工作但我仍然很好奇我们可以做什么方法从迭代器列表中擦除向量中的元素。

3 个答案:

答案 0 :(得分:1)

计划A: 你最好用std :: list改变std :: vector,删除后std :: list的迭代器不会无效。

B计划:

std::vector<int> newOne;
copy_if(oldOne.begin(), oldPOne.end(), std::back_inserter(newOne), [](){ //to test not in the map ~~ });
oldOne = std::move(newOne)

答案 1 :(得分:1)

使用索引而不是迭代器。替换

struct Ref {
    std::vector<RenderData>::iterator ref;
    std::function<int()> update;
    bool should_remove;
};
std::vector< std::vector<RenderData>::iterator> to_remove;

struct Ref {
    std::size_t ref;
    std::function<int()> update;
    bool should_remove;
};
std::vector< std::size_t> to_remove;

然后你的好主意与后代排序将工作。要通过索引调用ints.erase(ints.begin() + ref)

删除元素

对迭代器进行排序是一个错误的想法。如何实现向量迭代器是不可预测的。它们的排序顺序与指针/地址/索引的排序顺序非常小。

  

iterator erase(iterator pos); (直到C ++ 11)

     

迭代器擦除(const_iterator pos); (自C ++ 11起)

     

删除pos处的元素。

     

在擦除点或之后使迭代器和引用无效,包括end()迭代器。

答案 2 :(得分:1)

使用迭代器版本。 注意:

  1. 只有在重新分配时,迭代器才会失效。
  2. 只是用索引替换迭代器不会改变从向量中删除某些值时它们无效的事实。
  3. 使用索引仍然是一种更好的方法,因为稍后添加更多元素时它们不会失效。
  4. 方法: 使用不应删除的元素创建vector的副本

    using Element = std::string;
    using RenderData = int;
    struct Ref {
        std::vector<RenderData>::iterator itr;
        bool should_remove;
    };
    
    struct Main {
        std::vector<RenderData> ints;
        std::unordered_map<Element, Ref> elements;
        void remove_stuff(){
            std::vector<RenderData> localCopy;        
            localCopy.swap(ints);
            ints.reserve(localCopy.size());        
            for(auto it = elements.begin(); it != elements.end();) {
                Ref& ref = it->second;
                if(ref.should_remove) {
                    it = elements.erase(it);
                } else {
                    ints.push_back(std::move(*ref.itr));
                    ref.itr = ints.end() - 1;                
                    it++;
                }
            }            
        }
    };
    

    链接:https://godbolt.org/g/SouZ5E