Search code examples
c++stlunordered-set

why are elements of unordered_set not unique for custom equal_to


I am trying to understand unordered_set better. Mainly, to my understanding elements in an unordered_set should be unique up to equal_to operator. Therefore, I decided to test that by a small piece of code

#include <iostream>
#include <unordered_set>
using namespace std;

struct m_int
{
    int x;
};
// template specialization for std::hash
template<>
struct std::hash<m_int>
{
std::size_t operator()(m_int const& x) const noexcept
{

return hash<int>{}(x.x); 
}
};
//template specialization for std::equal_to

template<>
struct std::equal_to<m_int>
{
bool operator()(const m_int &lhs, const m_int &rhs) const 
{
    
return abs(lhs.x-rhs.x)<=3;
}
};
int main() {
    unordered_set<m_int> m={{1},{2},{3},{4}};
    for(auto&x:m)
        cout<<x.x<<' ';
    cout<<endl;
    cout<<m.count({2})<<endl;
    // your code goes here
    return 0;
}

My initial thought is that 1 would be inserted 2, and 3 would but 4 would be inserted.

The output I got was

4 3 2 1 
1

since according to my equal_to 1 and 2 are the same, then this set actually contains repetition, which is against the definition of the set. Why is that the case and how can I solve that?


Solution

  • Unordered containers have the following requirements for their hash and key equality functions:

    If two Keys are equal according to Pred, Hash must return the same value for both keys.

    This is not true for your container. 1 and 4, for example, compare equal but they'll (almost certainly) have different hash values. This results in undefined behavior.

    Another logical problem here: 1 is equal 4, and 4 is equal to 7, but 1 is not equal to 7. This does not compute, either.