目录
一、一个万用的 Hash Function
一般实现哈希函数的三种方式:普通函数 、 hash 函数对象 、hash() 函数的偏特化重写
函数对象作为哈希函数,设置不定序容器时,规定<容器中的元素,hash 函数对象名>,相比普通函数简便太多。
C++2.0 的新语法 — 标号1中,<typename... Type> 表示可以接收任意多个模板参数
<typename... Type>借用不定量的参数拆解开来并利用递归解决。
- hash_val() 函数(非标准库,其算法思想由用户实现,可以利用这种思想做出万能的 hash function),用来解决一个包含多个不同类型成员的类对象的哈希编码问题。其参数列表可以自定义个数,需要几个就放几个。
- n个参数被调整成 seed,n之后再次调用 hash_val第二版本 参数为 seed,1,n-1 ,用这个被分割出来的 1 去改 seed,剩下的 n-1 又会再次分割成 1,n-2,继续由这个 1 去改 seed,迭代直到被分成一个一个的,最后变成 seed+1 的 调用方法3解决。
- 改 seed :hash_combine,调用每个基本类型的 hash_function 再经过一系列加值与移位(本质上也是经验算法,借用了黄金比例值 1.618 的概念)。改完之后 seed 就是 hashcode。算出的 hashcode 是没有 %n 之前的值。
测试:
实现 hash() 对 Mystring 做偏特化版本。可以引用已有的偏特化或者利用上面的 hash_val 算法的思想。
二、tuple 用例
可以指定任意的元素,而且元素可以是任意的类型集合成为一个对象。
tuple 的使用
- 创造与初始化一个 tuple 的几种方式:tuple<类型名>(初始化列表) 与 make_tuple() 方法
- get<0>(对象名) 取 tuple 中的第一个元素,取出的元素可以进行单独复制。
- 两个不同类型的 tuple 甚至可以互相比较大小,可以互相赋值。
- tie(i1,f1,s1) = t3; 将 t3 中的所有元素拿出来附着到 三个变量中去。
typename... Tail 说明有很多个 type Tail... 有很多个Tail
class tuple<Head,Tail...> : private tuple<Tail...> 继承少一个模板参数下的自己(父类数据在内存分布的较上方),实现分解递归。
tuple 开放了两个函数 head() 和 tail() 可以外部使用。head 得到当前头数据,tail 获得除了头数据之外的整体。
三、type traits
旧版本的 C++,泛化的模板中,所有 回答算法的 关于类型的 5 个 typedef 即 5 个问题:默认构造、拷贝构造、复制运算。。。函数 是否为 trival (不重要)的,默认的答案都是 false ,即“重要的”。同时使用了 特化,对一些基本类型的这些问题的做出了 “不重要” 的回答。而对一些用户自定义的类或类型,就得由用户自己去写偏特化来回答这些问题。
3.1 type traits 的应用
C++ 新标准下,不再需要用户自己去写偏特化,可以通过提供的 traits 对类型直接提问。
type_traits_output()
几个问题:
- 一个类需不需要写析构函数? 只要类成员有指针就必须要写,如果没有指针多半不必写。
- 一个类需不需要写虚析构函数? 一个类如果要准备作为 base class 的话,才需要写虚析构函数。
&& move 构造函数
3.2 type traits 的实现
用模板对类型做操作
- 先做 remove_cv() 去掉 const 和 volatile(多线程关键字) 这这些无关的类型性质的影响。
- 丢给 helper,泛化情况下的所有类型回答 false, 符合偏特化的特定类型时才回答 true。
template<typename _Tp>
struct remove_const
{ typedef _Tp type; } //泛化,直接返回类型
template<typename _Tp>
struct remove_const<_Tp const>
{ typedef _Tp type; } //特化 const 时候的情况,返回去掉const 后的类型
像 is_class,is_union,is_enum,is_pod 的这些高级功能的实现都是编译器在编译过程中整理出来的数据,所分析得到的结果。
四、cout
cout 本质是 派生于 ostream 类(_IO_ostream_withassign)的一个对象,
- extern 表示在本文件之外,也能被使用。
- cout 类方法中重载了许多数据类型的输出方法。
- 未在 cout 重载范围内的,就要由用户自己在定义的类中提供输出运算符的重载。
五、moveable
5.1 moveable 的实现
- move ctor 操作,只拷贝了指针的值(参数初始化列表中实现)。不用做深层次的内存分配,即浅拷贝。
- 对于次数很多的拷贝动作,当涉及指针指向的元素的构造与赋值时,move 操作会极大地节省了时间。
- 采用 insert 操作调用构造函数,编译器(意识到要insert 的 buffer 之后不会再被使用了,所以才这样选择)就会自动选择 move 版本拷贝构造或者 非move 版本拷贝构造。
5.1 moveable 的测试
copy 即深拷贝的时间消耗很多
move copy 浅拷贝 与 swap 的消耗时间很少。用 move 拷贝的条件就是 拷贝之后 原来的东西不再使用。
M c11(c1);深拷贝时,c1不是临时对象,所以编译器不能自动选择 move copy ,要使用的话只能显示指定 M c12(std::move(c1));浅拷贝,使用结束后 c1 就作废了。
string类 带有 moveable 的特性。