[TOC]
STL ​
- STL是generic programming,强调data和method分开
和oop不一样 - 六大组件:容器,迭代器,算法,分配器,适配器,仿函数
container,iterator,algorithm,allocator,adapter,functor - Algorithm通过iterator确定container的范围,取container的元素
- 为什么list不能用::sort()来排序? 因为::sort()的源码里对迭代器进行了first+(last+first)/2这样的操作,这种操作只支持random access iterator
- 所有的algorithm最终涉及元素本身的操作都是比大小
- template
- 类模板
- 函数模板
类模板需要<>声明是什么类,函数模板不需要,他会进行argument deduction - member template
- 模板特化specialization、partial specialization
- 偏特化有两种,一种是个数上偏。两个泛化参数,只特化一个
- 另一种是范围上偏。T*或const T*这样的偏特化
容器 ​
顺序容器 ​
string ​
迭代器返回最后一个元素的下一个元素
string重新申请空间时,迭代器会失效
std::sort(str.begin(), str.end(), greater<char>());
greater<char>()是一个仿函数,表示从大到小排序
数组 ​
vector ​
vector 的reserve增加了vector的capacity,但是它的size没有改变!而resize改变了vector的capacity同时也增加了它的size! 原因如下:
- reserve是容器预留空间,但在空间内不真正创建元素对象,所以在没有添加新的对象之前,不能引用容器内的元素。加入新的元素时,要调用push_back()/insert()函数。
- resize是改变容器的大小,且在创建对象,因此,调用这个函数之后,就可以引用容器内的对象了,因此当加入新的元素时,用operator[]操作符,或者用迭代器来引用元素对象。此时再调用push_back()函数,是加在这个新的空间后面的。
array ​
valarray ​
双端队列 ​
- dequeue是分段连续
- insert(pos,val)的时候会先判断pos距离哪一段比较近
- dequeue的迭代器会模仿连续空间
- stack和queue都不允许遍历,所以不提供迭代器
- stack和queue也能以list为底层结构实现
- queue不可用vector实现,因为vector没有pop_front;stack可以
- stack和queue都不能选set或map做底层
queue ​
stack ​
链表 ​
list ​
list和vector的区别
- vector是动态数组,查找快,尾添加在不申请内存的情况下也快;插入删除慢
- list是双向循环链表,随机访问慢,插入删除快
forward_list ​
关联容器 ​
有序容器(红黑树) ​
- rbTree自动按顺序排列的,我们不应该用iterator改变树的节点的值,会破坏树的结构。但是map的data是可以改的,key不可改
- rbTree提供两种insert。insertUnique()和insertEqual()
- 仿函数的大小是0,编译器对于大小为0的class,实例化的对象大小为1
- 红黑树是双向的, 平衡排序二叉树
map ​
- 无法用set或multiset的iterator改变元素的key,可改变data
- map可以用[]直接插入,内部调用lower_bound()和insert()
multimap ​
- multimap不可用[]实现insertion
set ​
- 无法用set或multiset的iterator改变元素的值
- 因为set的key就是value
- algorithm提供了find(), set自己也提供了find,用后者
multiset ​
无序容器(散列表Boost) ​
hashtable:
bucket一般比元素个数多。
当检测到bucket的个数==元素个数时,会自动倍增到质数bucket的个数
并把原来的元素打散重新放rehash,放的位置等于这个数%bucket的个数
- bucket_count()
- max_bucket_count()
- load_factor()
- max_load_factor()这个值固定是1
unordermap ​
unordermultimap ​
unorderset ​
unordermultiset ​
hash_map ​
算法 ​
- container是class template
- algorithm是function template
- 算法看不到容器,只看到iterator
- 算法通常有两个版本,其中一个允许加入自己的运算规则
- accumulate
- function object函数对象,class或struct里只重载()
- for_each replace() replace_if() replace_copy()
- count() count_if()
- 不带count的容器arry,forward_list,vector,list,dequeue
- Assiciated container都自带count
- find()
算法里的find是循序查找
Associated container都有自己的find - sort
Associated container都没有sort
sort要求random access iterator,给list和forward_list会出错 - rbegin() rend()
- bool binary_search() 里面调用lower_bound()
迭代器 ​
- array和vector的迭代器是random access
- dequeue也是,queue和stack没有迭代器
- list是bidirectional
- forward list是forward
- map和set是bidirectional
- unordered_map set是bidirectional或者forward
- istream_iterator是input iterator
- istream_iterator是output iterator
- 不同类型的迭代器之间有继承关系
- 可以直接继承struct,里面只有几个typedef
分配器 ​
在vc里的Allocator只是通过::operator new和::operator delete完成allocate和deallocate
gunc2.9的alloc则不一样,它要尽量减少malloc的次数。一共16条链表负责n*8字节大小的申请。容器的大小会被调整到8的倍数,分到相应的链表那里,直接malloc一大块。然后再分块切割,切割出来的内存用链表串起来
gun4.9又改回普通的,alloc被保存在extension alloctors里的__pool_alloc。想用旧版:
vector<string, __gun_cxx_::__pool_alloc<string>> vec
仿函数 ​
- functor只为algorithm服务
- 就是一个class里重载了(),是函数对象
- 分类
- logical逻辑运算类
- Arithmetic算术运算类
- relational关系运算类
- 仿函数适配算法需要继承binary_function或者union_function
适配器 ​
- functor adapter bind2nd() not1()
- iterator adapter
- container adapter stack,queue