开发者

How to remove unique_ptr by pointer from a container?

Creating an object and giving ownership to a container using a unique_ptr is no problem. How would one remove an element by raw pointer?

std::set<std::unique_ptr<MyClass>> mySet;

MyClass *myClass = new MyCl开发者_Python百科ass();
mySet.insert(std::unique_ptr<MyClass>(myClass));

// remove myClass from mySet?


You will need to find the iterator corresponding to the myClass element and then pass that iterator to mySet.erase(). The iterator may be found using the std::find_if algorithm with a custom Predicate functor that understands how to dereference unique_ptr and compare it to the raw pointer myClass.

You can not use the overloaded size_t set::erase ( const key_type& x ); since the raw pointer (even if wrapped in a temporary unique_ptr) will not be found in mySet.


Not as pretty as I would've liked. But the following does the job:

#include <memory>
#include <set>
#include <iostream>

struct do_nothing
{
    void operator()(const void*) const {}
};

struct MyClass
{
    MyClass() {std::cout << "MyClass()\n";}
    MyClass(const MyClass&) {std::cout << "MyClass(const MyClass&)\n";}
    ~MyClass() {std::cout << "~MyClass()\n";}
};

int main()
{
    std::set<std::unique_ptr<MyClass>> mySet;

    MyClass *myClass = new MyClass();
    mySet.insert(std::unique_ptr<MyClass>(myClass));

    // remove myClass from mySet?
    std::set<std::unique_ptr<MyClass>>::iterator i =
        lower_bound(mySet.begin(), mySet.end(),
                    std::unique_ptr<MyClass, do_nothing>(myClass));
    if (i != mySet.end() && *i == std::unique_ptr<MyClass, do_nothing>(myClass))
        mySet.erase(i);
}


It seems i am able to retrieve an iterator using a custom Predicate with lower_bound. Since std::set is an ordered container, lower_bound should perform logarithmically.

std::set<std::unique_ptr<MyClass>>::iterator i =
    std::lower_bound(mySet.begin(), mySet.end(), myClass, MyPredicate<MyClass>());

template<class Type>
struct MyPredicate
{
    bool operator()(const std::unique_ptr<Type>& left, const Type* right) const
    {
        return left.get() < right;
    }
}


Still not the best solution but for the moment i go with:

PointerMap<MyFoo>::Type myFoos;

MyFoo * myFoo = new MyFoo();
myFoos.insert(PointerMap<MyFoo>::Item(myFoo));

The header is:

#include <map>
#include <memory>
#include <utility>

template<typename T>
struct PointerMap
{
    typedef std::map<T *, std::unique_ptr<T>> Type;

    struct Item : std::pair<T *, std::unique_ptr<T>>
    {
        Item(T * pointer)
            : std::pair<T *, std::unique_ptr<T>>(pointer, std::unique_ptr<T>(pointer))
        {
        }
    };
};


You might like the answer over here: Efficiently erase a unique_ptr from an unordered_set

That's for C++14, but I think applies to C++11 as well.

It is not pretty, but does the efficient thing — no scanning the container, but using proper hash-based lookup.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜