Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to define a Hash class for custom std::basic_string<> specialization class just like std::string?

I have a specialization of std::basic_string, say, string_t, and it the same as std::string except that the third template argument is my custom allocator.

std::basic_string<>

Question: How should I define a hash functor class for this specialization using hash functors already provided in C++ standard library?

I know how to define a Hash functor, but I don't know how to utilize existing std::hash<..> functors in std to define my custom one. I hesitate to write my own hashing operations, knowing it is reinventing the wheel and is unlikely to be better than std::hash<std::string>, since the only difference between string_t and std::string is just the allocator.

cppreference has some examples but they don't help me much - I don't want to construct a temporarystd::string object using my string_t object's c_str() method only to feed the temporary object into std::hash<std::string> to get the hash value, because it entails allocating temporary heap memory.

I'm using C++14 and I want to stick to standard library.

like image 489
Leedehai Avatar asked Apr 27 '18 08:04

Leedehai


People also ask

How do you write a hash function in C++?

The idea is to make each cell of hash table point to a linked list of records that have same hash function value. Let's create a hash function, such that our hash table has 'N' number of buckets. To insert a node into the hash table, we need to find the hash index for the given key.

What does std :: hash do?

std::hash<const char*> produces a hash of the value of the pointer (the memory address), it does not examine the contents of any character array.

Is STD hash unique?

That means you can only have 256 unique hashes of arbitrary inputs. Since you can definitely create more than 256 different strings, there is no way the hash would be unique for all possible strings.

Is STD hash good?

Since C++11, C++ has provided a std::hash< string >( string ) . That is likely to be an efficient hashing function that provides a good distribution of hash-codes for most strings.


1 Answers

Question: How should I define a hash functor class for this specialization using hash functors already provided in C++ standard library?

The short and sad answer is that there is no way to do this. The standard library does not offer hash functions for sequences of integral types.

Workarounds:

boost::hash is superior in every way to std::hash. I would suggest you define your std::hash specialisation in terms of it.

Furthermore, if you can, specify boost::hash<> as the hashing function for all unordered containers. You'll never regret it. std::hash is a half-formed library.

#include <string>
#include <cassert>
#include <unordered_set>
#include <boost/functional/hash.hpp>

struct my_alloc ...

using my_string = std::basic_string<char, std::char_traits<char>, my_alloc>;
std::size_t hash_value(::my_string const& s)
{
            return boost::hash_range(s.begin(), s.end());
}

namespace std {
    template<> struct hash<::my_string> 
    {
        std::size_t operator()(::my_string const& s) const
        {
            return hash_value(s);
        }
    };
}

int main()
{
    auto x = my_string("Hello");

    using Set1 = std::unordered_set<my_string, boost::hash<my_string>>;
    auto set1 = Set1 { x };

    auto h = std::hash<my_string>();
    auto hh = h(x);
    assert(hh == hash_value(x));
    return int(hh);
}
like image 123
Richard Hodges Avatar answered Oct 23 '22 05:10

Richard Hodges