Home > Back-end >  How to compute hash of std::weak_ptr?
How to compute hash of std::weak_ptr?

Time:11-28

So I have code that uses std::weak_ptr and maintains them in an std::set, and that works just fine -- and has worked for the last 5 or 7 years. Recently I thought I'd fiddle with using them in an std::unordered_set (well, actually in an f14::F14ValueSet) and for that, I would need a hash of it. As of now, there is no std::hash<std::weak_ptr>, so what should I do instead?

The answer seems to be "just hash the control block", as implied by this question and reply: Why was std::hash not defined for std::weak_ptr in C 0x?, but how do I get access to the control block? In glibc, it's located at __weak_ptr<>::_M_refcount._M_pi-> but that's private (and implementation specific). What else can I do?

One answer is "just wait": maybe someday there will be a standard owner_hash() for std::weak_ptr, but I'd prefer something available now.

CodePudding user response:

Make your own augmented weak ptr.

It stores a hash value, and supports == based off owner_before().

You must make these from shared_ptrs, as a weak ptr with no strong references cannot be hashed to match its owner; this could create two augmented weak ptrs that compare equal but hash differently.

template<class T>
struct my_weak_ptr {
  // weak ptr API clone goes here.  lock() etc.

  // different ctor:
  my_weak_ptr(std::shared_ptr<T>const& sp){
    if(!sp) return;
    ptr=sp;
    hash = std::hash<T*>{}(sp.get());
  }
  std::size_t getHash()const{return hash;}
  friend bool operator<(my_weak_ptr const& lhs, my_weak_ptr const& rhs){
    return lhs.owner_before(rhs);
  }
  friend bool operator!=(my_weak_ptr const& lhs, my_weak_ptr const& rhs){
    return lhs<rhs || rhs<lhs;
  }
  friend bool operator==(my_weak_ptr const& lhs, my_weak_ptr const& rhs){
    return !(lhs!=rhs);
  }
private:
  std::weak_ptr<T> ptr;
  std::size_t hash=0;
};

these have stable, sensible hashes. While a recycled object pointer results in a hash collision, so long as they don't share control blocks they won't be equal.

One warning: Use of aliasing constructor could result in pathological results. As equality is based on control block equality, not pointer value.

  • Related