MSVC 14.51 把 <hash_map> 和 <hash_set> 文件删掉了。它不是一次突然的标准库破坏,而是一笔拖了约 30 年、正式警告了 10 年的技术债。
这段历史大致是:
-
C++98 没有哈希容器
早期标准库只有基于有序树的 std::map / std::set。哈希表曾在 1995 年被提议加入标准,但因为标准制定时间不足而被搁置。
-
各家厂商自行补齐
SGI STL、Dinkumware、Metrowerks 等分别提供了自己的:
hash_map
hash_set
但这些实现的接口并不完全一致。Microsoft 的版本最终位于:
#include <hash_map>
stdext::hash_map<Key, Value>
注意它一直是 Microsoft 扩展,不是 std::hash_map,更不是 ISO C++ 标准的一部分。
-
标准故意选择了 unordered_map 这个新名字
2003 年的 WG21 提案 N1456 解释得很有意思:委员会原本也考虑沿用 hash_map,但当时各厂商已经存在大量“名字相同、接口略有不同”的实现。
如果标准也叫 hash_map,用户会分不清自己使用的是厂商扩展还是标准版本,厂商也很难保证兼容。因此委员会选择了:
std::unordered_map
std::unordered_set
“unordered” 还直接表达了它与 std::map 最重要的区别:没有按键排序的保证。
-
C++11 正式接管
C++11 标准化了 <unordered_map> 和 <unordered_set>。从此 <hash_map> 就成为一个历史兼容层,没有继续存在的标准化理由。
-
VS 2015 开始最后通牒
从 VS 2015 开始,包含 <hash_map> 默认就会触发硬错误:
<hash_map> is deprecated and will be REMOVED.
Please use <unordered_map>.
当时还可以定义:
_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS
绕过错误。这个宏名叫“silence warnings”,实际上绕过的是 #error,属于非常强烈的迁移通知。
-
十年后终于执行
2025 年 10 月,MSVC STL 维护者 Stephan T. Lavavej 提交了 PR #5764,说明原话是:
With 10 years of notice, it's finally time to deliver as promised.
该修改删除了约 850 行 <hash_map> / <hash_set> 实现,以及大量 TR1 和兼容性测试,随后进入 MSVC Build Tools 14.51。
为什么非删不可?
除了“不属于标准”,官方给出的实际工程原因还有:
- 阻止新代码继续绑定 MSVC 专有扩展;
- 减少复杂 STL 内部实现中的特殊分支;
- 减少测试、修复和新特性适配负担;
- 让维护者更容易判断标准容器代码是否正确;
- 旧接口已经有十年的明确迁移窗口。
所以这不是因为 hash_map 这种数据结构过时了。哈希表当然还在,只是标准版本叫 std::unordered_map。
一般迁移为:
// 旧代码
#include <hash_map>
stdext::hash_map<int, Widget> values;
// 新代码
#include <unordered_map>
std::unordered_map<int, Widget> values;
但如果旧代码传入了 stdext::hash_compare 或自定义第三模板参数,就不能只做文本替换。hash_map 把哈希和比较策略揉在一个 traits 类型里,而 unordered_map 将它们拆成 Hash 与 KeyEqual 两个模板参数,需要分别迁移。MSVC 14.51 中旧文件已经不存在,因此以前那个 _SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS 宏也救不了了。
|