unordered_map源码解析和个人理解
参考链接 https://blog.csdn.net/ddkxddkx/article/details/6555754
还有这个源码解析https://zrj.me/archives/1248
1.下面的代码结果是多少?
#include <unordered_map>
#include <cstring>
#include <iostream>
using namespace std;
class A // 自定义类型必须手写比较函数
{
public:A(): val(0) {}int get_val() const {return val;}bool operator== (const A& b) const {return val == b.get_val();}
private:int val;
};struct A_hash // 自定义类型必须手写哈希函数
{size_t operator() (const A& s) const{// return __stl_hash_string(s.c_str());return s.get_val()%10;}
};int main()
{A a;unordered_map<A, int, A_hash, equal_to<A> > m;m[a] = 1;A b;m[b] = 2;cout << m[a] << endl;return 0;
}
答案:2
为什么是2呢?
这要从unordered_map的原型来看
template<class _Key, class _Tp,class _Hash = hash<_Key>,class _Pred = std::equal_to<_Key>,class _Alloc = std::allocator<std::pair<const _Key, _Tp> > >class unordered_map
unordered_map<string, int>
相当于
unordered_map<string, int, hash<int>, equal_to<int>, allocator<pair<const string, int>>>
1.哈希函数
struct hash<int> {size_t operator()(int __x) const { return __x; }
};
如果是自定义类型,要自己实现哈希函数
2.比较函数
比较函数用于当哈希值对应的位置已经有值的时候,进行比较
3.显式具体化
hashtable.h
/// Base types for unordered_map.template<bool _Cache>using __umap_traits = __detail::_Hashtable_traits<_Cache, false, true>;template<typename _Key,typename _Tp,typename _Hash = hash<_Key>,typename _Pred = std::equal_to<_Key>,typename _Alloc = std::allocator<std::pair<const _Key, _Tp> >,typename _Tr = __umap_traits<__cache_default<_Key, _Hash>::value>>using __umap_hashtable = _Hashtable<_Key, std::pair<const _Key, _Tp>,_Alloc, __detail::_Select1st,_Pred, _Hash,__detail::_Mod_range_hashing,__detail::_Default_ranged_hash,__detail::_Prime_rehash_policy, _Tr>;// _Key std::pair<const _Keym _Tp>
typedef __umap_hashtable<_Key, _Tp, _Hash, _Pred, _Alloc> _Hashtable;
_Hashtable _M_h;explicit
unordered_map(size_type __n,const hasher& __hf = hasher(),const key_equal& __eql = key_equal(),const allocator_type& __a = allocator_type())
: _M_h(__n, __hf, __eql, __a)
{}
__umap_hashtable:
template<bool _Cache_hash_code, bool _Constant_iterators, bool _Unique_keys>struct _Hashtable_traits{using __hash_cached = __bool_constant<_Cache_hash_code>;using __constant_iterators = __bool_constant<_Constant_iterators>;using __unique_keys = __bool_constant<_Unique_keys>;};
_HashTable
下面是__cache_default
template<typename _Tp, typename _Hash>using __cache_default= __not_<__and_<// Do not cache for fast hasher.__is_fast_hash<_Hash>,// Mandatory to have erase not throwing.__detail::__is_noexcept_hash<_Tp, _Hash>>>;
template<typename _Key, typename _Value, typename _Alloc,typename _ExtractKey, typename _Equal,typename _H1, typename _H2, typename _Hash,typename _RehashPolicy, typename _Traits>class _Hashtable: public __detail::_Hashtable_base<_Key, _Value, _ExtractKey, _Equal,_H1, _H2, _Hash, _Traits>,public __detail::_Map_base<_Key, _Value, _Alloc, _ExtractKey, _Equal,_H1, _H2, _Hash, _RehashPolicy, _Traits>,public __detail::_Insert<_Key, _Value, _Alloc, _ExtractKey, _Equal,_H1, _H2, _Hash, _RehashPolicy, _Traits>,public __detail::_Rehash_base<_Key, _Value, _Alloc, _ExtractKey, _Equal,_H1, _H2, _Hash, _RehashPolicy, _Traits>,public __detail::_Equality<_Key, _Value, _Alloc, _ExtractKey, _Equal,_H1, _H2, _Hash, _RehashPolicy, _Traits>,
默认的哈希函数
__hash_code_M_hash_code(const _Key& __k) const{// code2// std::cout << "code2" << std::endl;return _M_h1()(__k); }
_M_h1():
const _H1&_M_h1() const { std::cout << "const_M_h1" << std::endl; return __ebo_h1::_S_cget(*this); }
__ebo_h1::_S_cget(*this):
using __ebo_h1 = _Hashtable_ebo_helper<1, _H1>;using __ebo_h2 = _Hashtable_ebo_helper<2, _H2>;
template<int _Nm, typename _Tp>struct _Hashtable_ebo_helper<_Nm, _Tp, true>: private _Tp{_Hashtable_ebo_helper() = default;template<typename _OtherTp>_Hashtable_ebo_helper(_OtherTp&& __tp): _Tp(std::forward<_OtherTp>(__tp)){ }static const _Tp&_S_cget(const _Hashtable_ebo_helper& __eboh){ return static_cast<const _Tp&>(__eboh); }static _Tp&_S_get(_Hashtable_ebo_helper& __eboh){ return static_cast<_Tp&>(__eboh); }};
返回一个H1,H1是什么?第六个参数
template<typename _Key,typename _Tp,typename _Hash = hash<_Key>,typename _Pred = std::equal_to<_Key>,typename _Alloc = std::allocator<std::pair<const _Key, _Tp> >,typename _Tr = __umap_traits<__cache_default<_Key, _Hash>::value>>using __umap_hashtable = _Hashtable<_Key, std::pair<const _Key, _Tp>,_Alloc, __detail::_Select1st,_Pred, _Hash, // 这是第六个参数__detail::_Mod_range_hashing, // _M_bucket_index__detail::_Default_ranged_hash,__detail::_Prime_rehash_policy, _Tr>;
就是用默认的哈希函数来计算键值
所以,对自定义类型,需要自己实现哈希函数与比较函数
插入:
operator[](const key_type& __k){ return _M_h[__k]; }
hashtable_policy.h
using __hashtable = _Hashtable<_Key, _Value, _Alloc, _ExtractKey,_Equal, _H1, _H2, _Hash,_RehashPolicy, _Traits>;template<typename _Key, typename _Pair, typename _Alloc, typename _Equal,typename _H1, typename _H2, typename _Hash,typename _RehashPolicy, typename _Traits>auto_Map_base<_Key, _Pair, _Alloc, _Select1st, _Equal,_H1, _H2, _Hash, _RehashPolicy, _Traits, true>::operator[](const key_type& __k)-> mapped_type&{__hashtable* __h = static_cast<__hashtable*>(this); // 这个只能在子类方法中使用__hash_code __code = __h->_M_hash_code(__k); // 计算哈希值std::size_t __n = __h->_M_bucket_index(__k, __code);__node_type* __p = __h->_M_find_node(__n, __k, __code);if (!__p){__p = __h->_M_allocate_node(std::piecewise_construct,std::tuple<const key_type&>(__k),std::tuple<>());return __h->_M_insert_unique_node(__n, __code, __p)->second;}return __p->_M_v().second;}
下面来看一看_M_bucket_index
std::size_t_M_bucket_index(const _Key&, __hash_code __c, std::size_t __n) const{//std::cout << "bucket2" << std::endl;return _M_h2()(__c, __n); }
看一看_M_h2:
const _H2&_M_h2() const { return __ebo_h2::_S_cget(*this); }_H2&_M_h2() { return __ebo_h2::_S_get(*this); }
返回了 H2
struct _Mod_range_hashing{typedef std::size_t first_argument_type;typedef std::size_t second_argument_type;typedef std::size_t result_type;result_typeoperator()(first_argument_type __num,second_argument_type __den) const noexcept{return __num % __den;}};
如果两个key相等的时候,不用插入
不相等,则在桶里面插入
查找:
两个key相等放回
不相等找下一个
函数原型
template <class _Tp>
struct equal_to : public binary_function<_Tp,_Tp,bool>
{bool operator()(const _Tp& __x, const _Tp& __y) const { return __x == __y; }
};
unordered_map源码解析和个人理解相关推荐
- Block源码解析和深入理解
Block源码解析和深入理解 Block的本质 Block是"带有自动变量值的匿名函数". 我们通过Clang(LLVM编译器)来将OC的代码转换成C++源码的形式,通过如下命令: ...
- FutureTask源码解析(2)——深入理解FutureTask 1
Future和Task 在深入分析源码之前,我们再来拎一下FutureTask到底是干嘛的.人如其名,FutureTask包含了Future和Task两部分. FutureTask实现了Runnabl ...
- Java源码解析:深入理解==和equals()
1.结论 1.1 == 1.所有原始数据类型,比较的是值 2.所有的对象比较的是内存地址 注意点:Integer类有对象池[-128,127] 1.2 equals()方法 1.未重写的equals( ...
- Laravel源码解析之从入口开始
前言 提升能力的方法并非使用更多工具,而是解刨自己所使用的工具.今天我们从Laravel启动的第一步开始讲起. 入口文件 laravel是单入口框架,所有请求必将经过index.php define( ...
- Hotspot 垃圾回收之oop_iterate(二) 源码解析
目录 1.java.lang.Class 1.1.Class实例中oop_size.klass等属性是哪来的? 1.2._offset_of_static_fields 1.3 为什么从_offset ...
- 彻底理解OkHttp - OkHttp 源码解析及OkHttp的设计思想
OkHttp 现在统治了Android的网络请求领域,最常用的框架是:Retrofit+okhttp.OkHttp的实现原理和设计思想是必须要了解的,读懂和理解流行的框架也是程序员进阶的必经之路,代码 ...
- 【转】Android事件分发机制完全解析,带你从源码的角度彻底理解(下)
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9153761 记得在前面的文章中,我带大家一起从源码的角度分析了Android中Vi ...
- [学习总结]7、Android AsyncTask完全解析,带你从源码的角度彻底理解
我们都知道,Android UI是线程不安全的,如果想要在子线程里进行UI操作,就需要借助Android的异步消息处理机制.之前我也写过了一篇文章从源码层面分析了Android的异步消息处理机制,感兴 ...
- jQuery源码解析(架构与依赖模块)第一章 理解架构
1-1 jQuery设计理念 引用百科的介绍: jQuery是继prototype之后又一个优秀的Javascript框架.它是轻量级的js库 ,它兼容CSS3,还兼容各种浏览器(IE 6.0+, F ...
最新文章
- java遍历给定目录,树形结构输出所有文件,包括子目录中的文件
- leetcode算法题--最大加号标志★
- 有机晶体数据库_技术专栏:一篇文章搞懂晶体学信息文件CIF及其获取方法
- 计算方法之迭代法求方程根
- Ubuntu 安装 cuda deb 指令 不要自动装9.2
- BZOJ 1491: [NOI2007]社交网络( floyd )
- java年利润编程题_[编程入门]利润计算-题解(Java代码)
- MyIbatis :不使用XML和注解@Mapper以及MapperScan
- as3中的 override
- iframe高度自适应的实现
- AMiner发布2022 AI 2000人工智能最具影响力学者名单
- 微型计算机常见的输入与输出设备,微型计算机的输入输出设备.doc
- Java添加、读取Excel公式
- VScode 控制台/终端乱码
- 测试无法测试的几乎苹果api实时搜索示例
- 多线程模式下保证事物的一致性
- 利用定时器实现倒计时
- STLINk驱动安装
- LaTeX 公式常用符号与常见问题解决
- 全智通A+常见问题汇总解答—A+库存损益编辑页面输入损益数量+损益结果!=当前库存