简体   繁体   English

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

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

I have a vector of int, and a map which contains as values some iterators pointing to the vector. 我有一个int的向量,以及一个包含指向向量的迭代器作为值的映射。 I need to remove keys from the map, and the vector element the value points to. 我需要从地图中删除键,以及值指向的向量元素。 My code look briefly like that: 我的代码看起来像这样:

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
}

I implemented an erase_if function that looked like this one . 我实现了一个看起来像这个erase_if函数。

So my initial code looked like that: 所以我的初始代码看起来像这样:

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

    return false;
});

It obviously didn't worked. 它显然没有用。 Erasing element makes other iterator to point on wrong object, and in some case out of bound. 擦除元素使其他迭代器指向错误的对象,在某些情况下超出绑定。 So I tried that: 所以我试过了:

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

And again, I ended up erasing the wrong elements sometimes. 而且,有时我最终会删除错误的元素。

Given iterators stored in some map, can I remove from the vector the elements the iterators are pointing to? 给定存储在某个映射中的迭代器,我可以从向量中删除迭代器指向的元素吗?


Update: 更新:

It seems in the last snippet I swapped some elements in the vector, making erasing the wrong elements. 似乎在最后一个片段中我交换了向量中的一些元素,使得删除了错误的元素。 Now it seem to work but I'm still curious what are the methods we can do to erase elements in a vector from an iterator list. 现在它似乎工作但我仍然好奇我们可以做什么方法从迭代器列表中擦除向量中的元素。

Plan A : You'd better change std::vector with std::list, the iterator of std::list won't be invalid after erase. 计划A:你最好用std :: list改变std :: vector,删除后std :: list的迭代器不会无效。

Plan B: 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)

Use indices instead of iterators. 使用索引而不是迭代器。 Replace 更换

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

with

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

And then your good idea with descendant sort will be working. 然后你的好主意与后代排序将工作。 To erase an element by index call ints.erase(ints.begin() + ref) 通过索引调用ints.erase(ints.begin() + ref)擦除元素

Sorting of iterators is a wrong idea. 迭代器的排序是错误的想法。 How vector iterators are implemented is not predictable. 如何实现向量迭代器是不可预测的。 It is a very small probability that their sort order is the same as for pointers/addresses/indices. 它们的排序顺序与指针/地址/索引的排序顺序非常小。

iterator erase( iterator pos ); 迭代器擦除(iterator pos); (until C++11) (直到C ++ 11)

iterator erase( const_iterator pos ); 迭代器擦除(const_iterator pos); (since C++11) (自C ++ 11以来)

Removes the element at pos. 移除pos处的元素。

Invalidates iterators and references at or after the point of the erase, including the end() iterator. 在擦除点或之后使迭代器和引用无效,包括end()迭代器。

Using the iterator version. 使用迭代器版本。 Note: 注意:

  1. Iterators are invalidated only when there is a reallocation. 只有在重新分配时,迭代器才会失效。
  2. Just replace iterators with index does not change the fact that they are invalid when some values are removed from the vector. 只是用索引替换迭代器不会改变从向量中删除某些值时它们无效的事实。
  3. Using indexes is still a better approach as they don't get invalidated when more elements are added later. 使用索引仍然是一种更好的方法,因为稍后添加更多元素时它们不会失效。

Approach: Create a copy of vector with elements that should not be removed 方法:使用不应删除的元素创建矢量副本

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

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

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

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