0

std :: remove(このアルゴリズムについてはここここで読んだ)とlist::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イテレータがあることがわかりましたが、同じNamedTypeが複数ある場合、これは機能しません。たとえば、オブジェクトo2をobjectList1に2回登録すると、オブジェクトが表示され、そのメンバー関数はすべての要素をループするため、namedObjectsInfo()メソッドによって呼び出されます(new_endイテレータは表示されません)。

正しく理解していれば、std :: removeを使用してコンテナから要素を削除する必要がありますか、この場合はstd::findとlist::Eraseの組み合わせを使用する必要がありますか?

4

3 に答える 3

5

コンテナに独自のremoveメソッドstd::listがある場合は、そのように、の代わりにそれを使用する必要がありますstd::remove。メソッドを持たないコンテナーのremove場合は、ここの他の回答で説明されている消去-削除のイディオムを使用する必要があります。

于 2012-12-26T19:53:36.597 に答える
3

std::removeコンテナ構造自体は更新されないため、イテレータ範囲の最後に「外部」要素が含まれることになります。コンテナを完全にクリーンアップするには、削除と消去を組み合わせる必要があります。

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

std::list::remove()ただし、IronMensanの回答で述べたように、リストでの操作用に最適化され、多段階の削除がなくなるため、ケースで使用する方が適切です。

于 2012-12-26T19:48:59.390 に答える
1

両方を使用する必要があります。removeこれは、要素が削除されたことをコンテナに通知しないeraseためremoveです(4つのオブジェクトが含まれていると見なされるため、最後に奇妙な結果になります)。

void removeNamedType(NamedType& o)
{
    objectList_.erase(
        std::remove(objectList_.begin(), objectList_.end(), &o),
        objectList_.end()); 
}
于 2012-12-26T19:52:19.310 に答える