第一部分 Sequence containers序列式容器
for(auto ch:s)//虽然用了auto,但auto到底应该是什么应该心里有数
1、容器分类与测试
侯捷:
-
在我要用到定义的时候,才去在函数之前定义他而不是全部集中在开头。
-
测试单元分开放。
namespace jj06{
int a;
int func(){
}
}
最好不要用分配器allocator,少量取内存可以用new搭配delete。
9
OOP是将data与method放一起,GP是分开放。
13 list
在C++中,规定了带有参数的是后置++,没有参数的是前置++,没有意义,只是区分之用。
前++,后++,int前++可以加两次,用的是reference&,后++不可以加两次,返回的是值。
list的继承关系较为复杂,父类大小多少,子类也是多少。
15 traits 萃取出特性
算法向iterator提出的问题,有些iterator不是class,是退化的(c++原始的指针),需要traits来提取分辨,再交给算法。
16 vector深入探索
没有空间扩大空间的时候,先是找一块连续的原来两倍大的空间,然后将原来的和新加入的元素移过去。安插点之后的元素也要拷贝过去,因为可能是insert调用此扩大函数。
所以每次扩大空间的时候会耗费很多资源。
泛化,偏特化
traits接收的五个问题,五个变量会经过很复杂的名词定义转变给到traits。
17 array,forward_list探索
array,没有构造,析构函数,vector和array都是连续空间,所以iterator都是原始指针,不是class。
forwardlist是单项链表,和list类似,list是双向的。
18-19 deque
deque是双向开口的,vector是单向开口的。控制中心是一个vector。旧版deque可以指定缓冲区大小,新版不可以。deque对外声称是连续的,虽然他不是连续的。insert很巧妙,如果在块的前面位置insert,就移动前面的元素,如果在后面一点,就移动后面的元素。
用后++调用前++,用后–调用前–,知名库人都这么写。
此处有一个图
因为声称是连续的,所以有+=的操作,能一次移动一格以上,此时,判断是否跨越块,进行相应的移动。
queue stack
封掉deque的一些功能,就是queue和stack了,list也可以作为两者的底层结构,但是很可能更慢,stl不采用,stack可选择vector做为底层,queue不行。
两者都不能遍历,也没有iterator。两者都不可以选set或map做为底层。
做为底层结构 | deque | list | vector | set、map |
---|---|---|---|---|
stack | √ | √ | √ | × |
queue | √ | √ | × | × |
第二部分 associative - container关联容器
查找和插入非常快,相当于数据库,用一个key去找value。红黑树和散列表是常见的底层结构。
20 rb_tree红黑树
是平衡搜索树。begin永远记录最左边的节点。不应用迭代器去赋值,会破坏树的形式,这就是map的key,但是key对应的data可以改。红黑树并没有规定是否能放重复的key ,看你的需求。
为了符合handle and body柄体模式,所以在主体里没有多少操作的内容,而在外面另有一个implementation函数。
21 set、multiset
set是container adapter,操作都包给底层结构去做了,他自己不用做,有些人都不认为他们是一类容器。
如何禁止大家通过iterator修改key,可以设置iterator的类型为const_iterator。
identity函数,就是接受一个x,传回一个x,一致性。
22 map,multimap
operator[]里用了lower_bound二分搜索函数,如果找到了,返回元素,如果没有找到,返回最适合放元素的位置。
23-24 hashtable
哈希表,如果有碰撞,就放在这个桶(bucket)的链表里往后排(很多桶),但是链表太长也会造成查找不便。如果链表长度超过桶长度,就倍增,然后选择附近素数作为新的桶数。
按照计算,class作为成员不占空间,但是因为技术原因,还是占1个字节。
hashfunction hashcode hash_function是最重要的函数,用来将对象转化成一个数字放入table里排列,如果本身就是整型,返回自身即可,如果不是,有char的转换提供,没有的话自己可以写。
hashtable就是取余数放进对应篮子bucket。
25 以hashtable为基础的map,multimap,set,multiset
25的视频内容和23一样。。
26 unordered容器
set和map一般都用红黑树实现,因为性能好
map: map内部实现了一个红黑树,该结构具有自动排序的功能,因此map内部的所有元素都是有序的。
unordered_map: unordered_map内部实现了一个哈希表,因此其元素的排列顺序是杂乱的,无序的。
就是hash_set hash_map hash_multimap等的hash一词替换为unordered变为unordered_set,unordered_map等。
第三部分 算法
27 算法
算法看不到容器,只能通过迭代器进行运算。
28 迭代器的分类
前面6分钟和27一模一样。
iterator_category | 容器 | |
---|---|---|
forward | 单向前进 | 。。 |
bidirectional | 双向前进 | |
random | 随机访问下标 |
从下往上是继承关系。
仅仅继承一些typedef也有好处那就是减少重新抄写。
29 迭代器的分类对算法影响的实例
一个小技巧:临时对象,就是无名对象,
类型()
很简单就做出来了。
distance,advance
此函数计算两迭代器之间的距离。如果是random_access,可以直接相减;如果是input类型,需要一步步前进,计算距离。
advance类似,是前进或后退迭代器的函数。
copy,destroy
copy使用范围很广,可以将任一容器的任一段copy到任任地方。因为其用了很多泛化和特化,通过多次判断是否是普通指针还是容器,是否指向char等,来分化各种情况,达到最适合最快方案。其中有些方法用到了memmove(),一c语言函数,方便快捷。
什么算是不重要的,析构函数等是自动生成的,里面没有内容的,算是不重要的函数。
算法代码会暗示你传入什么类型的iterator,虽然都能接收,但是不合适的iterator算法可以选择不对其处理,算法特意修改模板参数名来暗示适应范围。
30 算法实例
function object(函数对象)也叫仿函数。
predicate:一种判断条件
自带的成员函数比标准库里的更快。
end()指的地方与rbegin()一样,但是取数方式稍微不同,所以需要套一个适配器adapter进行改造。
31 仿函数functor
六大部件里最简单的。
仿函数是一些额外的准则,来辅助实现算法,类似于sort里面cmp函数。
如果自己写仿函数,并希望以后能易于修改,被adapter改造,融入stl,需要继承一些给定的基类。
32 适配器
很多适配器。
-
函数适配器
-
容器适配器containers
-
迭代器适配器
一、容器适配器
stl提供两个queue和stack,他们修饰deque而成,通过选择性的封闭、开放一些接口形成。
二、函数适配器
bind2nd
到底是函数的调用,还是传入一个对象,c++里讲了很多次了,后面直接加一个小括号的,是创建了一个临时对象。
没听完,下课后再仔细听,学习
bind
占位符,可以用来代替参数
auto fn_hello=bind(hello,_1,2)//占位符为_1
三、迭代器适配器
reverse_iterator
没重点
inserter
copy函数本质上只能赋值,但是加入了inserter,可以进行插入操作,并且会自动扩容。
四、未知适配器
ostream
能适配ostream的适配器,通过重置copy函数里operator函数的方式,使operator里面定死的过程得到改变。
istream
。。
第四部分 stl周边技术与应用
40 一个万用的哈希算法
使用仿函数创建一个类。利用c++函数可变参数模板,设置三个同名参数(还能设置传入任意个参数),进行递归操作,最终算出一个hash code。
41 tuple
这是一个神奇的函数定义,
tuple<int,string,double> tup;
能组合任意类型,任意数量,为对象。
和上一个万能哈希函数比,这里也用了递归,是用继承父类实现递归。
42 type traits
带指针就一定要写析构函数
44 cout
如果是你自己的类型,需要你自己去重载<<,来cout。
45 moveable元素
深拷贝:欢迎欢迎,浅拷贝很危险,深拷贝不只是指针本身还有后面的都拷贝。
copy是深拷贝,move是浅拷贝,只交换3个指针。move版本有&&。
参考
t.csdn.cn
stl源码剖析笔记 写的挺好