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

时间:2012-12-26 19:43:19

标签: c++ stl

我尝试使用std :: remove从列表中删除elemet(指向指定类型的指针)(我已阅读此算法herehere)以及列表的组合:: erase和std :: find。

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

#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的组合?

3 个答案:

答案 0 :(得分:5)

当容器有自己的remove方法时,如std::list那样,您应该使用它而不是std::remove。对于没有remove方法的容器,您应该使用其他答案中描述的擦除 - 删除习惯用法。

答案 1 :(得分:3)

std::remove不会更新容器结构本身,因此您最终会在迭代器范围的末尾使用“无关”元素。为了完全清理容器,您需要结合删除和擦除:

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

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

答案 2 :(得分:1)

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

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