1.2 STL
此处结合侯捷老师《STL 源码剖析》与个人见解编写,如有错误,请指出。
1.2.1 序列类容器
1.2.1.1 vecotor
vector是单向开口的连续线性空间,且在尾部进行添加/删除,对随机访问的效率高。
但是在头部进行添加/删除操作效率会变得极低。
虽然说vector的内存空间是连续的,但是在添加新元素的时候内存空间并不是动态添加到已有内存空间后的,而是申请一片更大(一般是已有空间的2倍)的内存空间,返回将已有的数据拷贝过去。
这里可以注意到产生了拷贝操作,如果容器内对象是自定义对象,最好可以写一个移动构造函数,来减少容器在拷贝过程中产生的性能消耗。
顺便一提,在vector中,一开始申请的空间,一般会比其中的实际存贮的要大:
vector<int> vec = {12,15,17,180,16};
一开始申请的空间便是8,这样在添加对象的时候不需要一直申请新的内存空间,只有在到达8的容量上限的时候才需要申请,且每次申请都是上次的2倍,也可以防止过于频繁的申请内存空间。
实际容量上限可以通过capacity()来获取。
所以,vector的动态增加大小,实际上只是不断的申请更大空间,而不是在原来的内存空间上接续。(这也是在迭代器使用时,不改变遍历容器大小的原因)
为避免大量插入导致的大量拷贝性能消耗,可以使用reserve()提前申请内存空间,减少性能消耗,但是不确定是否会有大量内存空间被使用的时候最好还是别申请大片空间。
1.2.1.2 list
list是一种双向链表,也是因此对空间的利用十分精准,每次删除/添加对象的操作都可以在常数时间内完成.
其进行插入操作(insert)和接合操作(splice)时,迭代器不会失效,进行删除操作也只会有一个指向被删除对象的迭代器失效。
1.2.1.3 deque
deque是双向开口的连续线性空间(伪)。
容器是动态的以分段连续空间组合而成,随时新增内存空间并链接起来,所以不会有vector中不断申请新空间并拷贝的情况产生,也是因此,deque没有vector的reserve()功能。
其分段连续空间是通过维护一个中控器来完成的,中控器中存储着指向每一个分段空间的指针。
值得一提的是,中控器的容量上限是有限的,也就是说,其达到容量上限后,也需要申请空间,然后把指针拷贝过去。
PS:中控器很像vector,对吧 :)
1.2.1.4 queue
由deque为底部结构,并封闭前端入口,尾端出口,便为一个queue。
底层与deque相同,不再赘述,stack同理。