代码路径:http://www.sgi.com/tech/stl/download.html
1, list 类
list内部为一个双向链表。用一个节点A表示结束节点。结束节点无有意义数据,用来标示链表结束。此节点的next为链表开始节点(第一个有效数据节点)。链表的最后一个有效数据节点的next为A。
iterator 的本质是一个Node指针,++时返回next, --时返回previous
size()操作比较费时,需要遍历整个链表。
2, vector 类
内部为一动态数租, iterator的本质是一个指针。erase,insert 操作将会移动后边所有元素。内存不够时,会重新分配两倍内存。默认构造函数数组长度为0,第一次分配为1.
3,deque类
内部一个动数组的数组。第一维度的数组存储一个_M_map的指针,_M_map是一个一维数组,在_M_map中存储实际的数据。这样当存储空间扩充时,仅仅需要重新拷贝第一维度,第二维度的数据不需要变化。而且两端都可以独立的扩充和缩减。
template <class _Tp, class _Alloc>
class _Deque_base {
......
protected:
_Tp** _M_map;
size_t _M_map_size;
iterator _M_start;
iterator _M_finish;
......
};
与vector类对比,deque需要更多的管理代码,效率不如vector高。但是deque方便两端扩充,特别是当数据量比较大,而且变化更频繁时,deque可以减少更多的数据移动。
4,queue类
内部是一个deque,但是仅仅暴露出部分接口。queue没有迭代器。
5,string 类
string类的存储结构与vector相同,也是一维数组。默认构造函数会设定数组长度为8.
6,map 类
map类的内部为一红黑树,存取都为对数复杂度。当使用[]运算符时,如果元素key不存在,map类会插入一个元素默认值在key位置,并返回。map类的由begin()到end()的遍历是按照key的顺序遍历的。即二叉排序树的中序遍历。每个iterator实际上是一个二叉树的节点指针。
7,hash_map类
hash_map的本质上是一个hash_table类,核心的存储结构是一个vector,vector 存储的是链表的首地址。当hash后的key发生冲突时,会沿此链表依次存储。即采用拉链法解决hash地址冲突。 key元素对应的实际存储位置是hash(key)/vector.size()。当元素数量增长到一定程度时, 将对内部vector会进行扩容。扩容时会将vector中的每个元素按照新的size依次copy到一个临时的vector,最后将此vector swap回核心的存储vector。当删除元素时,内部的存储空间大小不会改变。所以hash_table的存储空间会一直增大直到析构。即使调用clear()也只会清除链表值,核心的vector大小不会回缩。当使用[]运算符时,如果元素key不存在,map类会插入一个元素默认值在key位置,并返回。hash_table的遍历是无序的。begin() 是vector中最左边一个非空节点。
8,set类
内部实现与map相同,为红黑树
9,hash_set 类
内部存储与hash_map相同,为哈希表
10, 内存分配 allocate
1)stl 将new操作的 ::new operator 和constructor 分开实现 (以及 ::delete和deconstructor)以提高效率。例如新建一个指定长度的vector时,只调用malloc 分配内存。当调用push_back时,才调用constructor
2)stl 中调用析构函数时会进行类型判断。如果是基本数据类型(int,char,double, int*.....)则跳过析构调用。
3)stl 中分配内存时采用分级处理,当要求分配内存小于128byte时,使用内存池,当大于128B时,直接调用malloc。用来防止内存碎片。