我应该使用 std::remove 从列表中删除元素吗?

Posted

技术标签:

【中文标题】我应该使用 std::remove 从列表中删除元素吗?【英文标题】:Should I use std::remove to remove elements from a list? 【发布时间】:2012-12-26 19:43:19 【问题描述】:

我尝试使用 std::remove (我已阅读有关此算法 here 和 here)以及 list::erase 和标准::查找。

这是我为此目的编写的代码:

#include <iostream>

#include <list>
#include <functional>
#include <string>
#include <algorithm>


class NamedType

    std::string name_; 

    public: 
        NamedType (const char* name)
            : 
                name_(name)
            

        void info()
        
            std::cout << name_ << ": NamedType::update()" << std::endl;
        
;

class NamedTypeList

    std::list<NamedType*> objectList_; 

    public: 

        void addNamedType(NamedType& o)
        
            NamedType* oPtr = &o; 
            objectList_.push_back(oPtr);
        

        void removeNamedTypeWithFind(NamedType& o)
        
            std::list<NamedType*>::iterator removedNamedType = std::find(
                objectList_.begin(), objectList_.end(), &o);

            if (removedNamedType != objectList_.end())
            
                objectList_.erase(removedNamedType); 
            
        

        void removeNamedType(NamedType& o)
        
            std::remove(objectList_.begin(), objectList_.end(), &o); 
        

        void namedObjectsInfo()
        
            std::for_each(objectList_.begin(), objectList_.end(), 
                std::mem_fun(&NamedType::info)); 
        
;

using namespace std;

int main ()

    NamedType o1("o1"); 
    NamedType o2("o2"); 
    NamedType o3("o3"); 
    NamedType o4("o4"); 

    NamedTypeList objectList1; 
    NamedTypeList objectList2; 

    objectList1.addNamedType(o1); 
    objectList1.addNamedType(o2); 
    objectList1.addNamedType(o3); 
    objectList1.addNamedType(o4); 

    objectList2.addNamedType(o1); 
    objectList2.addNamedType(o2); 
    objectList2.addNamedType(o3); 
    objectList2.addNamedType(o4); 

    cout << "Registered objects into objectList1:" << endl;
    objectList1.namedObjectsInfo(); 

    cout << "Registered objects into objectList2:" << endl;
    objectList2.namedObjectsInfo(); 

    cout << "Removing o2 object from objectList1 with remove" << endl;

    objectList1.removeNamedType(o2); 
    objectList1.namedObjectsInfo(); 


    cout << "Removing o2 object from objectList2 with std::find" << endl;

    objectList2.removeNamedTypeWithFind(o2); 
    objectList2.namedObjectsInfo(); 

; 

我不明白为什么当我调用 objectList1.removeNamedType(o2); 时会得到以下输出:

Removing o2 object from objectList1 with remove
o1: NamedType::update()
o3: NamedType::update()
o4: NamedType::update()
o4: NamedType::update()

我无法理解文档:我知道有一个 new_end 迭代器显示范围的新结束,但是如果我有多个相同的 NamedTypes,这将不起作用。例如。如果我在 objectList1 中注册对象 o2 两次,它将是可见的,并且它的成员函数将由 namedObjectsInfo() 方法调用,因为它遍历所有元素(它看不到 new_end 迭代器)。

如果我理解正确,我什至应该使用 std::remove 从容器中删除元素,还是在这种情况下使用 std::find 和 list::erase 的组合?

【问题讨论】:

【参考方案1】:

当容器有自己的remove 方法时,就像std::list 一样,你应该使用它而不是std::remove。对于没有 remove 方法的容器,您应该使用此处其他答案中描述的擦除删除习语。

【讨论】:

【参考方案2】:

std::remove 不会更新容器结构本身,因此您最终会在迭代器范围的末尾出现“无关”元素。为了彻底清理容器,需要结合remove和erase:

    void removeNamedType(NamedType& o)
    
        objectList_.erase(std::remove(objectList_.begin(), objectList_.end(), &o), objectList_.end()); 
    

但是,正如 IronMensan 的回答中提到的,更好的方法是在您的情况下使用 std::list::remove(),因为它针对列表上的操作进行了优化并摆脱了多阶段删除。

【讨论】:

【参考方案3】:

您必须同时使用removeerase,因为remove 不会通知您的容器它已取出元素(它仍会认为它包含 4 个对象,因此您最终会遇到奇怪的情况最后)。

void removeNamedType(NamedType& o)

    objectList_.erase(
        std::remove(objectList_.begin(), objectList_.end(), &o),
        objectList_.end()); 

【讨论】:

以上是关于我应该使用 std::remove 从列表中删除元素吗?的主要内容,如果未能解决你的问题,请参考以下文章

有没有更好的替代 std::remove_if 从向量中删除元素的方法?

std::remove_if 中的 const 参数

std::remove_extent 可以用来做啥?

从列表中删除元组删除了一些但不是全部

如何从列表中删除元组

如何根据元组的索引值从列表中删除重复的元组,同时保持元组的顺序? [复制]