Using a std::unordered_set of std::unique_ptr

cfa45ca55111016ee9269f0a52e771 picture cfa45ca55111016ee9269f0a52e771 · Jul 25, 2013 · Viewed 7.4k times · Source

Assume I have a set of unique_ptr:

std::unordered_set <std::unique_ptr <MyClass>> my_set;

I'm not sure what's the safe way to check if a given pointer exists in the set. The normal way to do it may be to call my_set.find (), but what do I pass as a parameter?

All I have from the outside is a raw pointer. So I have to create another unique_ptr from the pointer, pass it to find() and then release() that pointer, otherwise the object would get destructed (twice). Of course, this process can be done in a function, so the caller can pass the raw pointer and I do the conversions.

Is this method safe? Is there a better way to work with a set of unique_ptr?

Answer

Xeo picture Xeo · Jul 25, 2013

You can also use a deleter that optionally doesn't do anything.

template<class T>
struct maybe_deleter{
  bool _delete;
  explicit maybe_deleter(bool doit = true) : _delete(doit){}

  void operator()(T* p) const{
    if(_delete) delete p;
  }
};

template<class T>
using set_unique_ptr = std::unique_ptr<T, maybe_deleter<T>>;

template<class T>
set_unique_ptr<T> make_find_ptr(T* raw){
    return set_unique_ptr<T>(raw, maybe_deleter<T>(false));
}

// ...

int* raw = new int(42);
std::unordered_set<set_unique_ptr<int>> myset;
myset.insert(set_unique_ptr<int>(raw));

auto it = myset.find(make_find_ptr(raw));

Live example.