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

How can I erase elements from a vector given a list of iterator?

本文关键字:情况下 向量 元素 删除 列表 迭代器      更新时间:2023-10-16

我有一个 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函数。

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

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

再一次,我有时会删除错误的元素。

给定迭代器

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


更新:

似乎在最后一个片段中,我交换了矢量中的一些元素,从而擦除了错误的元素。现在它似乎有效,但我仍然很好奇我们可以做些什么来从迭代器列表中擦除向量中的元素。

使用迭代器版本。注意:

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

方法:使用不应删除的元素创建矢量的副本

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

计划 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)

使用索引而不是迭代器。取代

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)擦除元素

迭代器的排序是一个错误的想法。矢量迭代器的实现方式是不可预测的。它们的排序顺序与指针/地址/索引的排序顺序相同的可能性非常小。

迭代

器擦除( 迭代器 POS (;(至C++11(

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

删除位置处的元素。

使擦除点处或之后的迭代器和引用失效,包括 end(( 迭代器。

相关文章: