为何std::map可接受std::pair作为键,而std::unordered_map却不行?
为啥std::map能拿std::pair当键,std::unordered_map却不行?
这个问题戳中了C++两个常用容器的核心差异,我给你拆解明白:
先看std::map这边
std::map是基于红黑树的有序关联容器,它的工作逻辑是靠键的大小关系来维护有序性的,只要求键类型支持**小于比较运算符(operator<)**就行。
巧了,std::pair默认就自带了operator<的重载!它是按字典序来比较的:先比较pair的第一个元素,如果相等再比较第二个元素。所以你直接把std::pair<int,int>作为std::map的键,编译器完全能找到需要的比较逻辑,自然编译毫无压力,就像你写的那段代码一样~
再看std::unordered_map的问题
std::unordered_map是基于哈希表的无序关联容器,它的工作逻辑依赖两个东西:
- 能给键生成唯一(尽可能少碰撞)哈希值的哈希函数
- 判断两个键是否相等的相等运算符(operator==)
std::pair虽然默认有operator==,但C++标准库并没有为std::pair提供默认的std::hash特化!也就是说,编译器找不到怎么给std::pair<int,int>计算哈希值,自然就会抛出一堆编译错误。
怎么解决这个问题?
你需要自定义一个哈希函数,然后告诉std::unordered_map用它。举个简单的实现例子:
#include <unordered_map> #include <utility> #include <functional> using namespace std; typedef pair<int, int> int_pair; // 自定义针对int_pair的哈希结构体 struct PairHash { size_t operator()(const int_pair& p) const { // 组合两个int的哈希值,这里用移位异或的方式减少碰撞 auto hash_first = hash<int>{}(p.first); auto hash_second = hash<int>{}(p.second); return hash_first ^ (hash_second << 1); } }; int main() { // 第三个模板参数指定我们的自定义哈希函数 unordered_map<int_pair, int, PairHash> m; return 0; }
这里提一句:标准库为啥不给std::pair默认哈希?因为哈希函数的设计要平衡效率和碰撞率,不同场景(比如键的取值范围、业务需求)适合的哈希方式不一样,标准库没法给出一个通用的最优实现,所以把这个选择权交给了开发者。
内容的提问来源于stack exchange,提问作者Max
相关产品推荐
相关产品推荐

