c++debuggingc++11identitystdhash

Why std::hash<int> seems to be identity function


#include <iostream>

int main() {
    std::hash<int> hash_f;
    std::cout << hash_f(0) << std::endl;
    std::cout << hash_f(1) << std::endl;
    std::cout << hash_f(2) << std::endl;
    std::cout << hash_f(3) << std::endl;
}

I compile with "g++ main.cpp -std=c++11" and then the result is :

0
1
2
3

Why is this happening? I don't use any library and I don't have a specialized hashing function.

Addendum : I wanted to define the hash for an unordered_set of unordered_set of int with the hash of a set being the sum of its components hashs, but if it's just identity it's not cool because the hash of {2,4} is the same than the hash of {1,5}. The simplest way to avoid that is may be to use the std::hash double function.


Solution

  • The other answers cover the rationale behind the identity function very well. To address your addendum:

    I wanted to define the hash of an unordered_set as the sum of its components hashs, but if it's just identity it's not cool because the hash of {2,4} is the same than the hash of {1,5}. The simplest way to avoid that is may be to use the std::hash function.

    As you can see, using the + operator to combine hashes is not the best idea. To be more robust, you could use the XOR (^) operator, or take inspiration from the approach taken, e.g., by boost::hash_combine (details in this SO post):

    seed ^= hash_value(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
    

    As an example, for your two integer pairs (1,5 / 2,4), and a seed of 0, this would work out to

    uint32_t seed = 0;
    seed ^= 1 + 0x9e3779b9 + (seed << 6) + (seed >> 2);
    seed ^= 5 + 0x9e3779b9 + (seed << 6) + (seed >> 2);
    // 3449077526
    
    uint32_t seed = 0;
    seed ^= 2 + 0x9e3779b9 + (seed << 6) + (seed >> 2);
    seed ^= 4 + 0x9e3779b9 + (seed << 6) + (seed >> 2);
    // 3449077584