简体   繁体   中英

boost::hash/std::tr1::hash not returning same hash for copied const char*

I have following code:

#include <cstring>
#include <boost/functional/hash.hpp>
#include <iostream>

int main(int argc, char **argv)
{
    const char *str1 = "teststring";

    // copy string
    size_t len = strlen(str1);
    char *str2 = new char[len+1];
    strcpy(str2, str1);

    // hash strings
    std::cout << "str1: " << str1 << "; " << boost::hash<const char*>()(str1) << std::endl;
    std::cout << "str2: " << str2 << "; " << boost::hash<const char*>()(str2) << std::endl;

    delete[] str2;

    return 0;
}

I always get the same hash for str1 (as expected). But str2 differs - in fact it returns a different hash every time I run the programm.

Can someone explain why?

As Linuxios suggested, it's hashing the pointer value, not the string. I did a quick test with this code:

char str1[] = "teststring";
std::cout << "str1: " << str1 << "; " << boost::hash<const char*>()(str1) << std::endl;
str1[3] = 'x';
std::cout << "str1: " << str1 << "; " << boost::hash<const char*>()(str1) << std::endl;

And here's the output. Note that the string is different but since the pointer is the same the hash matches.

str1: teststring; 158326806782903
str1: tesxstring; 158326806782903

The only change you need to make is to tell boost it's hashing a std::string and it will give you matching hashes. Your underlying data can remain char* .

std::cout << "str1: " << str1 << "; " << boost::hash<std::string>()(str1) << std::endl;
std::cout << "str2: " << str2 << "; " << boost::hash<std::string>()(str2) << std::endl;

Result:

str1: teststring; 10813257313199645213
str2: teststring; 10813257313199645213

If you actually want the hash of the string not the pointer then you can either use the boost::hash_range function or a custom loop using hash_combine and write your own hash function object. boost::hash<std::basic_string<...> > does hashes using hash_range , with has_range in turn using hash_combine .

eg something like this:

struct CStringHash : public std::unary_function<char const*, std::size_t> {
    std::size_t operator()(char const* v) const {
        std::size_t seed = 0;
        for (; *v; ++v) {
            boost::hash_combine(seed, *v);
        }
        return seed;
    }
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM