std::unordered_map用std::pair作键的哈希效率:是否需用boost::hash?
关于std::unordered_map键为std::pair<uint, const Foo*>的哈希实现问题
问题描述
我使用键类型为<std::pair<uint, const Foo*>>、值类型为std::vector<uint>的std::unordered_map,插入和查询操作未出现编译或运行错误,但不确定当前代码是否为最优实现。请问编译器会为该键类型生成高效的哈希函数吗?是否应该改用boost::hash?
相关代码
class Foo { public: Foo():var1(0){}; ~Foo(); void func(int a) { var1 = a; } int var1; }; int main() { Foo f1; f1.func(10); const Foo* fp = &f1; std::unordered_map<std::pair<uint,const Foo*>,std::vector<uint>> umap1; umap1[std::make_pair(1,fp)].emplace_back(100); }
解答
首先明确:C++标准并没有为std::pair<T1, T2>提供std::hash的特化实现。你的代码能编译运行,大概率是依赖了编译器的非标准扩展(比如GCC的libstdc++在部分版本中对std::pair做了哈希特化),但这种实现不具备跨编译器/平台的移植性,不建议依赖。
关于哈希效率
就算编译器提供了非标准的std::pair哈希实现,它的效率和冲突控制也不一定理想。这类默认实现通常只是简单组合两个元素的哈希值(比如直接异或),而指针类型的哈希一般是直接取地址值,简单组合容易出现较高的冲突概率,影响unordered_map的查询性能。
是否需要改用boost::hash?
boost::hash对std::pair有官方特化,是经过充分测试的成熟实现,它的hash_combine逻辑能更合理地组合两个元素的哈希值,有效降低冲突率,同时具备良好的移植性。如果你的项目已经依赖Boost库,这是很稳妥的选择。
替代方案:自定义哈希函数
如果不想引入Boost依赖,也可以自己实现针对std::pair<uint, const Foo*>的哈希函数,可控性更强:
struct PairHash { std::size_t operator()(const std::pair<uint, const Foo*>& p) const { // 先分别计算两个元素的哈希值 std::size_t hash_first = std::hash<uint>{}(p.first); std::size_t hash_second = std::hash<const Foo*>{}(p.second); // 用更合理的方式组合哈希值(参考boost::hash_combine的逻辑) hash_first ^= hash_second + 0x9e3779b9 + (hash_first << 6) + (hash_first >> 2); return hash_first; } };
之后在声明unordered_map时指定哈希函数即可:
std::unordered_map<std::pair<uint, const Foo*>, std::vector<uint>, PairHash> umap1;
总结
- 现有代码的编译依赖非标准扩展,移植性差;
- 默认哈希实现的冲突控制和效率未必理想;
- 优先选择
boost::hash(若项目已依赖Boost),或自定义哈希函数(无额外依赖),这两种方案都比依赖编译器扩展更可靠。
内容的提问来源于stack exchange,提问作者Pirate
相关产品推荐
相关产品推荐

