Search code examples
c++hashunordered-set

C++ unordered_set's count and find don't work if it uses a custom class type as the key


I'm having some issues using unordered_set with my specialized hash function. I can insert elements without an issue, but when I try to find other elements using find or count it doesn't work. it can't find the elements that are already in the set.

Here's my hash function:

template <class T>
inline void hash_combine(std::size_t& seed, const T& v)
{
    std::hash<T> hasher;
    seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}

namespace std {
template<> 
    struct hash<Node>
    {
        std::size_t operator()(const Node &node) const
        {
            size_t seed = 0;
            hash_combine(seed, node.getX());
            hash_combine(seed, node.getY());
            return seed;
        }
    };
}

My Node class have bunch of other member variables but I'm only combining X and Y. This should be enough since I can safely assume there cannot be 2 Nodes with same X and Y values. This is the fist time I'm getting my hands dirty with template specialization, am I doing something wrong? I think I might not be hashing them correctly.

Here's an example to further clarify my issue:

Let say I have a set called mySet that contains 4 Nodes(X Y) : <1 7> <2 7> <3 7> <1 8>

bool find1(Node *node)
{   
    unordered_set<Node*>::const_iterator it = mySet.find(node);
    return (it != mySet.end()); //will be false
}

bool find2(Node *node)
{
    return !mySet.count(node); //will be 1 (!0)
}

cout << find1(new Node(1,7)) << endl; // returns 0

cout << find2(new Node(1,7)) << endl; // returns 1

Anyone have any idea why element lookups don't work?

Thanks


Solution

  • Because your unordered_set contains Node* and not Node, the pointers are being searched for and not the objects themselves. I don't know why find2 would return 1, unless by coincidence you have 2 objects allocated to the same place.

    If you tried to use a hashing function that took a Node* it wouldn't work either, because unordered_set also requires a working == operator to compare elements.