参考链接 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源码解析和个人理解相关推荐

  1. Block源码解析和深入理解

    Block源码解析和深入理解 Block的本质 Block是"带有自动变量值的匿名函数". 我们通过Clang(LLVM编译器)来将OC的代码转换成C++源码的形式,通过如下命令: ...

  2. FutureTask源码解析(2)——深入理解FutureTask 1

    Future和Task 在深入分析源码之前,我们再来拎一下FutureTask到底是干嘛的.人如其名,FutureTask包含了Future和Task两部分. FutureTask实现了Runnabl ...

  3. Java源码解析:深入理解==和equals()

    1.结论 1.1 == 1.所有原始数据类型,比较的是值 2.所有的对象比较的是内存地址 注意点:Integer类有对象池[-128,127] 1.2 equals()方法 1.未重写的equals( ...

  4. Laravel源码解析之从入口开始

    前言 提升能力的方法并非使用更多工具,而是解刨自己所使用的工具.今天我们从Laravel启动的第一步开始讲起. 入口文件 laravel是单入口框架,所有请求必将经过index.php define( ...

  5. Hotspot 垃圾回收之oop_iterate(二) 源码解析

    目录 1.java.lang.Class 1.1.Class实例中oop_size.klass等属性是哪来的? 1.2._offset_of_static_fields 1.3 为什么从_offset ...

  6. 彻底理解OkHttp - OkHttp 源码解析及OkHttp的设计思想

    OkHttp 现在统治了Android的网络请求领域,最常用的框架是:Retrofit+okhttp.OkHttp的实现原理和设计思想是必须要了解的,读懂和理解流行的框架也是程序员进阶的必经之路,代码 ...

  7. 【转】Android事件分发机制完全解析,带你从源码的角度彻底理解(下)

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9153761 记得在前面的文章中,我带大家一起从源码的角度分析了Android中Vi ...

  8. [学习总结]7、Android AsyncTask完全解析,带你从源码的角度彻底理解

    我们都知道,Android UI是线程不安全的,如果想要在子线程里进行UI操作,就需要借助Android的异步消息处理机制.之前我也写过了一篇文章从源码层面分析了Android的异步消息处理机制,感兴 ...

  9. jQuery源码解析(架构与依赖模块)第一章 理解架构

    1-1 jQuery设计理念 引用百科的介绍: jQuery是继prototype之后又一个优秀的Javascript框架.它是轻量级的js库 ,它兼容CSS3,还兼容各种浏览器(IE 6.0+, F ...

最新文章

  1. java遍历给定目录,树形结构输出所有文件,包括子目录中的文件
  2. leetcode算法题--最大加号标志★
  3. 有机晶体数据库_技术专栏:一篇文章搞懂晶体学信息文件CIF及其获取方法
  4. 计算方法之迭代法求方程根
  5. Ubuntu 安装 cuda deb 指令 不要自动装9.2
  6. BZOJ 1491: [NOI2007]社交网络( floyd )
  7. java年利润编程题_[编程入门]利润计算-题解(Java代码)
  8. MyIbatis :不使用XML和注解@Mapper以及MapperScan
  9. as3中的 override
  10. iframe高度自适应的实现
  11. AMiner发布2022 AI 2000人工智能最具影响力学者名单
  12. 微型计算机常见的输入与输出设备,微型计算机的输入输出设备.doc
  13. Java添加、读取Excel公式
  14. VScode 控制台/终端乱码
  15. 测试无法测试的几乎苹果api实时搜索示例
  16. 多线程模式下保证事物的一致性
  17. 利用定时器实现倒计时
  18. STLINk驱动安装
  19. LaTeX 公式常用符号与常见问题解决
  20. 全智通A+常见问题汇总解答—A+库存损益编辑页面输入损益数量+损益结果!=当前库存

热门文章

  1. iSCSI存储技术全攻略
  2. 国内卫星通信技术发展及应用概述
  3. 去中心化存储项目终极指南 | Filecoin, Storj 和 PPIO 项目技术对比(下)
  4. 全栈JVM框架Micronaut通向1.0版本之路
  5. 百度编辑器(ueditor)@功能之获取坐标
  6. 《Windows核心编程》学习笔记(10)– 同步设备I/O与异步设备I/O
  7. 如何识别AWARD的BIOS-ID
  8. 亮剑:PHP,我的未来不是梦(3)
  9. Oozie 出现 ClassNotFoundException 解决方法
  10. linux centos7 xen虚拟机 安装方法