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?
std::unique_ptr is a smart pointer that owns and manages another object through a pointer and disposes of that object when the unique_ptr goes out of scope. The object is disposed of, using the associated deleter when either of the following happens: the managing unique_ptr object is destroyed.
Use unique_ptr when you want a single pointer to an object that will be reclaimed when that single pointer is destroyed. Use shared_ptr when you want multiple pointers to the same resource.
make_unique prevents the unspecified-evaluation-order leak triggered by expressions like foo(unique_ptr<X>(new X), unique_ptr<Y>(new Y)) . (Following the advice "never say new " is simpler than "never say new , unless you immediately give it to a named unique_ptr ".)
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.
Note that the ability to do heterogenous lookups on standard containers is subject of some proposals.
http://cplusplus.github.io/LWG/lwg-proposal-status.html lists
Especially the latter looks like it would cover your use case.
For now, here is an IMO not very pretty but working alternative workaround (O(n)):
#include <iterator> #include <iostream> #include <algorithm>  #include <unordered_set> #include <memory>  #include <cassert>  struct MyClass {};  template <typename T> struct RawEqualTo {     RawEqualTo(T const* raw) : raw(raw) {}      bool operator()(T const* p) const           { return raw == p; }     bool operator()(std::unique_ptr<T> const& up) const           { return raw == up.get(); }    private:     T const* raw; };   using namespace std; int main() {     std::unordered_set <std::unique_ptr <MyClass>> my_set;      my_set.insert(std::unique_ptr<MyClass>(new MyClass));     my_set.insert(std::unique_ptr<MyClass>(new MyClass));      auto raw = my_set.begin()->get();      bool found = end(my_set) != std::find_if(begin(my_set), end(my_set), RawEqualTo<MyClass>(raw));     assert(found);      raw = new MyClass;      found = end(my_set) != std::find_if(begin(my_set), end(my_set), RawEqualTo<MyClass>(raw));     assert(!found);      delete raw; }   Warning It's also very inefficient, of course.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With