i want to store a set of (smart) pointers in a hash set, either <boost/unordered_set>. After 10 seconds of thought, i came up with this hash function:

typedef boost::shared_ptr<myType> ref_t;
struct SharedPtrHash : public std::unary_function<ref_t, std::size_t> {                        
    std::size_t operator()(ref_t const& obj) const {
      return reinterpret_cast<std::size_t>( obj.get() );
    }
};

My question is: is this hash a good idea? i'm entertaining the thought that this hash will have zero or very few collisions (maybe there is some prime-number modulus under the hood spoiling all my fun).

Further Details on purpose: The purpose of the hash is for recycling storage of big objects, so i need a fast way to detect if a big object is already in the bin.

in case it is not, what would be an ideal hash for pointers, either smart or dumb ones?

有帮助吗?

解决方案

If you want to detect objects that are not identical even though their contents might be equal, you have no choice but to use the address of the object in the hash. The only question is whether to use the address directly or to run it through a formula. Dividing by sizeof(mytype) would tighten up the holes in the distribution.

Edit: Here's an untested template implementation that should work with all shared_ptr types, along with an equal_to function to complete the requirements for std::unordered_set. Don't use this generic implementation if you have other objects that require a hash based on the value instead of the pointer.

template<typename T>
size_t hash(const std::shared_ptr<T> & ptr)
{
    return ((size_t) ptr.get()) / sizeof(T);
}

template<typename T>
bool equal_to(const std::shared_ptr<T> & left, const std::shared_ptr<T> & right)
{
    return left.get() == right.get();
}

其他提示

The following code compiles perfectly (GCC 4.7, Boost 1.47):

#include <boost/unordered_set.hpp>
#include <boost/shared_ptr.hpp>

struct Foo { };

int main()
{
  boost::unordered_set<boost::shared_ptr<int>> s;
  boost::shared_ptr<int> pi(new int);
  s.insert(pi);

  boost::unordered_set<boost::shared_ptr<Foo>> t;
  boost::shared_ptr<Foo> pf(new Foo);
  t.insert(pf);
}

The default Boost.Hash hash function for integral types is the identity function, so I don't think doing the same for pointers is a bad idea. It would have the same collision ratio.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top