GCC7环境下std::unordered_map与hash_map的find()对存在键返回空问题
问题根因
该问题本质是哈希函数与相等判断逻辑不匹配:
- 自定义的
eqfunc是按字符串内容判断两个const char*键是否相等 - 但
std::hash<const char*>的标准行为是对指针的内存地址做哈希,而非对指针指向的字符串内容做哈希
GCC4.7下能正常运行的原因是旧版本GNU扩展的std::hash_map对const char*类型做了非标准特化,哈希逻辑为计算字符串内容;升级到GCC7后,无论是新版hash_map还是标准std::unordered_map都遵循标准行为,仅哈希指针地址,就出现了内容相同但地址不同的键无法命中的问题:插入时用的是字符串常量的地址,查找时用的是std::string内部缓冲区的地址,二者地址不同哈希值不同,大概率不会落到同一个哈希桶,自然找不到对应键,甚至不会触发eqfunc执行,这也是eqfunc执行没有规律的原因——只有刚好两个键哈希值相同落到同一个桶的时候才会调用相等判断。
修复方案
不需要修改业务逻辑,仅需新增自定义哈希函数按字符串内容计算哈希,替换customMap声明里的哈希模板参数即可,侵入性极低:
- 新增自定义哈希函数
struct hash_cstr { size_t operator()(const char* s) const { size_t res = 0; // 常用的字符串哈希算法,可根据业务需要替换为其他实现 for (; *s; ++s) res = res * 131 + static_cast<unsigned char>(*s); return res; } };
- 修改
customMap的模板参数,替换原有默认哈希函数
// 采用unordered_map的版本 template <typename T> class customMap : public std::unordered_map<const char*, T, hash_cstr, eqfunc> {}; // 若要保留原有hash_map实现,改为以下版本即可 // template <typename T> class customMap : public std::hash_map<const char*, T, hash_cstr, eqfunc> {};
注意事项
该方案的前提是:插入到map中的const char*指向的字符串生命周期与map本身的生命周期匹配,不会出现插入后字符串内存被释放、产生野指针的情况。如果原有业务逻辑在GCC4.7下运行稳定,说明该前提已经满足,无需额外调整。
内容的提问来源于stack exchange,提问作者kane.zorfy
相关产品推荐
相关产品推荐

