C++ 如何从给定迭代器列表的向量中删除元素?

C++ 如何从给定迭代器列表的向量中删除元素?,c++,vector,c++14,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向量和一个映射,其中包含一些指向该向量的迭代器作为值。我需要从地图中删除关键点,并且向量元素的值指向。我的代码大致如下所示:

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(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?
}
std::要删除的向量;
擦除_if(元素,[&](自动和元素){
//基于字符串内容的条件
if(元素第二个应删除){
移走。放回(元素。第二。参考);
返回true;
}
返回false;
});
//按降序排序
std::sort(to_remove.begin()、to_remove.end()、std::greater{});
//东西
用于(自动删除(&it:要删除){
ints.erase(它);//没有什么会出错的,对吗?
}
同样,我有时会删除错误的元素

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


更新:

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

计划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)
std::vector newOne;
复制_if(oldOne.begin()、oldPOne.end()、std::back_inserter(newOne),[](){//以测试不在映射中~~});
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::vector::iterator ref;
功能更新;
布尔应该被移除;
};
std::vector删除;

struct Ref{
标准:尺寸参考;
功能更新;
布尔应该被移除;
};
要删除的std::vector
然后,您关于后代排序的好主意就会起作用。通过索引调用擦除元素的步骤
ints.erase(ints.begin()+ref)

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

迭代器擦除(迭代器位置);(直到C++11)

迭代器擦除(常量迭代器位置);(从C++11开始)

移除位置处的元素

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


使用迭代器版本。 注:

  • 迭代器只有在重新分配时才失效
  • 仅用索引替换迭代器并不会改变这样一个事实,即当从向量中删除某些值时,迭代器无效
  • 使用索引仍然是一种更好的方法,因为它们不会在以后添加更多元素时失效
  • 方法: 创建包含不应删除的元素的向量副本

    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++;
                }
            }            
        }
    };
    
    使用Element=std::string;
    使用RenderData=int;
    结构参考{
    std::vector::迭代器itr;
    布尔应该被移除;
    };
    主结构{
    std::向量整数;
    std::无序的_映射元素;
    void remove_stuff(){
    std::向量本地拷贝;
    localCopy.swap(ints);
    ints.reserve(localCopy.size());
    for(auto-it=elements.begin();it!=elements.end();){
    Ref&Ref=it->second;
    如果(参考应移除){
    它=元素。擦除(它);
    }否则{
    内部推回(标准::移动(*ref.itr));
    ref.itr=ints.end()-1;
    it++;
    }
    }            
    }
    };
    

    链接:

    底线是——不要将迭代器存储到内部向量项。如果调整向量的大小,可能会发生迭代器无效。@PaulMcKenzie我有一个函数,在调整大小时,可以将元素从映射重新同步到向量,因此这暂时不是问题。也许有了指数,它可以更快或更容易做到。虽然你的建议是正确的,但不遵循它会导致我目前的痛苦。我有一个函数,可以在调整大小时将元素从映射重新同步到向量——只有当你能够毫无疑问地识别可能发生失效的所有位置时,这个函数才是好的。我会使用索引,并删除元素,而不是在处理每个项目时转发。@PaulMcKenzie我会使用索引——这是我担心的,我可能需要进行一些重构。简短回答:使用索引。长答案,如果你给出更多的上下文,比如这些数据结构是什么,以及你想对它们做什么操作,那么可能有更好的选择。
    std::list
    的速度太慢了。B计划可能对某人有效,但我个人会避免它,因为它很复杂,而且需要额外的分配。我想你想快速删除它。你说std::列表太慢了,也许这不对。您可以调用std::list的“splice”API,这不会导致元素复制,迭代器也不会无效。尝试“无效拼接(常量迭代器位置,列表&x,常量迭代器i)”,将应该删除的添加到新列表中。删除这个列表~~好吧,确实有很多数据,
    std::list
    在添加/删除元素时速度更快,但是当它来自于对它的迭代时,它会完全破坏缓存:(你可能会提供更多的上下文。如果你坚持使用vector,这没关系,你的解决方案是有意义的。但是我会使用'std::set'(降序)而不是排序。然后foreach删除迭代器指向的元素。此解决方案基于std::vector的实现。但请确保这适用于所有平台?谢谢!我还注意到,我在一些操作之间调用了resync函数。我设法使其工作,但此解决方案似乎比我的更可靠。我设法使排序+擦除在循环中工作。然而,您的解决方案显然是最好的,甚至是最好的
    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++;
                }
            }            
        }
    };