cpp20规范 vs2019 STL库 unordered_map源码分析(整理后上传)

(1) unordered_map 模板有如下的模板调用和包含关系。
cpp20规范 vs2019 STL库 unordered_map源码分析(整理后上传)_第1张图片
绿箭头1 处的模板类,继承了绿箭头2 , 绿箭头2 又继承了红框模板。但红框模板有一个泛化版本和一个特化版本,选择哪一个呢?
经过源代码查找,_Hasher = hash<_Kty>,和 _Keyeq = equal_to<_Kty>里都没有 is_transparent 的定义。而哈希时int 整数应该是最常用的情况。所以应该是透明容器。以下做了运行验证。先修改STL源文件,如下图,添加两个验证函数
cpp20规范 vs2019 STL库 unordered_map源码分析(整理后上传)_第2张图片
再进行打印输出:
cpp20规范 vs2019 STL库 unordered_map源码分析(整理后上传)_第3张图片
所以应该是继承了泛化版本,就是透明的哈希容器。虽然,还不知道透明是啥意思。只是这个模板里强制了一个类型引用。
这个结论先这么认为。把源码改回去。继续,随后补充。

(2)vs2019里,哈希函数的效率如何,能避免哈希冲突么?
这个哈希函数的算法很复杂。不太容易明白,是数学问题。我们先看看这个哈希函数的使用效果。
cpp20规范 vs2019 STL库 unordered_map源码分析(整理后上传)_第4张图片
以上的图里,给出了vs2019哈希函数的源码。我们测试一下这个函数的运行效果:
cpp20规范 vs2019 STL库 unordered_map源码分析(整理后上传)_第5张图片
如上图,往16个元素的数组里存储15个数,竟然没有发生哈希冲突。这个函数属实优秀,完美。所以,我们可以放心大胆的哈希了。
再附上一张哈希函数的实验图。
cpp20规范 vs2019 STL库 unordered_map源码分析(整理后上传)_第6张图片
为什么要单独测试这里哈希函数的效率和计算结果呢?因为如果出现哈希冲突,按我的理解,STL库源码的设计是,把后待插入的list节点,插入到已在哈希表里的list节点的前面。就是说后到来的数据节点,反而离list的头部更近。无序map里维护了一个list链表,把无序map里的所有数据节点串起来。这是哈希表扩容时候,要访问的数据来源。但从实验可见,找到这样一个哈希冲突太难了。只能仔细阅读分析源码,凭借c++语法和代码逻辑来体会STL库编写大师的想法了。谢谢

(3)条目2是下午写的。出去散步时想到,如何产生哈希冲突。把大量数据映射到很小的数组里,必然会产生哈希冲突。
如下图这样的实验:
cpp20规范 vs2019 STL库 unordered_map源码分析(整理后上传)_第7张图片
从中挑选出了5个会产生哈希冲突的值来插在8个槽位的哈希容器里。如下图:
cpp20规范 vs2019 STL库 unordered_map源码分析(整理后上传)_第8张图片
我们编写如下代码,生成无序map:
cpp20规范 vs2019 STL库 unordered_map源码分析(整理后上传)_第9张图片
从上图,还得知了无序map在64位编程环境下的大小是80个字节,这个数值计算,编译器考虑了内存对齐。
打断点,跟踪变量 u 的内存,把所有内存数据拿到后,证明我们的这个结论是正确的,这也说明咱们对源代码的理解是正确的。这样是省事的做法,避免了汇编指令级别的跟踪:因为如果出现哈希冲突,STL库源码的设计是,把后待插入的冲突list节点,插入到已在哈希表里的list节点的前面。就是说后到来的哈希冲突的数据节点,反而离list的头部更近
以下的图是简单的手算的哈希表的元素节点插入过程:
cpp20规范 vs2019 STL库 unordered_map源码分析(整理后上传)_第10张图片
经内存上的数据的地址的验证,咱们的猜测是正确的。并附上无序map的数据结构,随后整理电脑版。
cpp20规范 vs2019 STL库 unordered_map源码分析(整理后上传)_第11张图片
谢谢。至此,解决了源码阅读中的一个疑问。

你可能感兴趣的:(c++容器类模板的相关源码分析,c++,哈希算法,开发语言)