lornova
lornova

Reputation: 6943

key vs. hash in a std::unordered_map

I often need a container where an hash is associated to an arbitrary object (collisions are theoretically possible if two different objects have the same hash).

In C++98 I would use template<class Key, class T> class std::map using Key as the hash computed on T:

struct object;
typedef std::string object_hash;

object_hash compute_hash(const object& obj);

std::map<object_hash, object> hash_map;

object_hash insert_or_assign(const object& obj)
{
    object_hash hash = compute_hash(obj);
    hash_map[hash] = obj;
    return hash;
}

std::pair<bool, object> get_at(const object_hash& hash)
{
    std::map<object_hash, object>::iterator iter = hash_map.find(hash);
    if( iter == hash_map.end() )
        return std::pair<bool, object>(false, object());
    else
        return std::pair<bool, object>(true, iter->second);
}

But starting from C++11 we have hashed containers so I expected something like:

template<class T, class Key = std::hash<T>> class std::hashed_map

with the requirement to provide a custom std::hash for type T, but instead we have

template<class Key, class T, class Hash = std::hash<Key>> class unordered_map

which does not apply to my scenario where the key is the hash itself, and there is no other "key" concept related to the arbitrary object.

Similar to what I expected is:

template<class Key, class Hash = std::hash<Key>> class unordered_set

but there are no lookup functions based on hash.

In modern C++ is there a built in container that uses hashes and has a lookup interfaces based on these hashes?

Upvotes: 1

Views: 1645

Answers (2)

Wizard
Wizard

Reputation: 1072

Originally the unordered_map was called hash_map, then the ISO C++ committee wisely renamed it, because the important difference between std::map and std::unordered_map is not that the first uses binary trees while the latter uses hashes, but that the first is ordered while the latter guarantees constant-time complexity.

So the fact that std::unordered_map uses hashes internally is little more than an implementation detail: you only need to provide an std::hash specialization if the key is a custom type (and the key is unfrequently a custom type). Apart from that, you should forget about the internal hashes of this container.

Despite some comments, if your key is the hash then there’s absolutely nothing wrong with you C++98 implementation. You can keep using it in C++ >= 11, updating and tiding it to the new language facilities where possible.

Upvotes: 2

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275878

You have a map not a hash map; the fact your key is a hash is irrelevant to the container.

About the only salient feature is that you rarely care about the order of hashes; so unordered map is probably best.

Take your old solution, replace map with unordered map, replace less operstion with equal and a hash (possibly down) to 64 bits. For example, the classic pointer hash is just reinterpret_cast<unit_ptr>( key ).

Upvotes: 2

Related Questions