c++c++11stdunordered-setweak-ptr

How to make a c++11 std::unordered_set of std::weak_ptr


I have a set like this: set<weak_ptr<Node>, owner_less<weak_ptr<Node> > > setName;

It works fine. But I would like to change it to an unordered set. However, I get about six pages of errors when I do that. Any ideas how to do that?

After looking through all the pages of error messages I found to lines that might help.

/usr/include/c++/4.7/bits/functional_hash.h:60:7: error: static assertion failed: std::hash is not specialized for this type
/usr/include/c++/4.7/bits/stl_function.h: In instantiation of ‘bool std::equal_to<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = std::weak_ptr<Node>]’:

Solution

  • Please read Richard Hodges answer below as mine is incorrect, despite being the accepted solution.


    Since unordered_sets are hash-based you have to provide a hash function object for the std::weak_ptr data-type.

    If you take a look at the unordered_set template-parameters

    template<class Key,
        class Hash = std::hash<Key>,
        class Pred = std::equal_to<Key>,
        class Alloc = std::allocator<Key> >
        class unordered_set;
    

    you'll notice that std::unordered_set provides you with a default std::hash<> template parameter. But since std::hash does only provide specializations for a specific set of data types, you might have to provide your own.

    The error-message you quoted tells you, that no std::hash<> specialization for std::weak_ptr<> exists, so you have to provide your own hashing function for that:

    template<typename T>
    struct MyWeakPtrHash : public std::unary_function<std::weak_ptr<T>, size_t> {
       size_t operator()(const std::weak_ptr<T>& wp)
       {
          // Example hash. Beware: As zneak remarked in the comments* to this post,
          // it is very possible that this may lead to undefined behaviour
          // since the hash of a key is assumed to be constant, but will change
          // when the weak_ptr expires
          auto sp = wp.lock();
          return std::hash<decltype(sp)>()(sp);
       }
    };
    

    Edit: You also need to provide an equality function, since no std::equal_to for weak_ptr is provided. Taking a possible way to do this from "Equality-compare std::weak_ptr" on Stackoverflow:

    template<typename T>
    struct MyWeakPtrEqual : public std::unary_function<std::weak_ptr<T>, bool> {
    
       bool operator()(const std::weak_ptr<T>& left, const std::weak_ptr<T>& right)
       {
          return !left.owner_before(right) && !right.owner_before(left);
       }
    };
    

    All combined this gives us the following:

    std::unordered_set<std::weak_ptr<T>,
                       MyWeakPtrHash<T>,
                       MyWeakPtrEqual<T>> wpSet;