一、vector概述
- vector的使用语法可以参考文章之前的几篇文章,总的来说:vector是可变大小数组
- 特点:
- 支持快速随机访问。在尾部之外的位置插入或删除元素可能很慢
- 元素保存在连续的内存空间中,因此通过下标取值非常快
- 在容器中间位置添加或删除元素非常耗时
- 一旦vector内存不足,重新申请内存之后,和原vector相关的指针,引用,迭代器都失效。内存重分配耗时很长
- 通常,使用vector是最好的选择,如果没有什么特殊要求,最好使用vector
- 与其他容器的比较:
vector | 可变大小数组。支持快速随机访问。在尾部之外的位置插入或删除元素可能很慢 |
deque | 双端队列。支持快速随机访问。在头尾插入/删除速度很快 |
list | 双向链表。只支持双向顺序访问。在list中任何位置进行插入和删除的速度都很快 |
forward_list | 单向链表。只支持单向顺序访问。在链表任何位置进行插入和删除操作速度都很快 |
array | 固定大小数组。支持快速随机访问。不能添加或删除元素 |
string | 与vector相似的容器,但专门用于保存字符。随机访问快。在尾部插入或删除速度快 |
二、vector定义摘要
- vector定于与<stl_vector.h>头文件中
三、vector的迭代器
- vector维护的是一个连续线性空间,所以不论其元素类别是什么,普通指针都可以作为vector的迭代器而满足所有必要条件
- vector迭代器支持有操作有(普通指针也具备):
- operator*、operator->、operator++、operator--、operator+、operator-、operator+=、operator-=
- vector支持随机存取,而普通指针正有着这样的能力,所以,vector提供的是随机访问迭代器(Random Access iterators)
- vector的迭代器定义如下:
- 例如:
四、vector的数据结构
- vector的数据结构非常简单:一个线性连续空间
- 下面介绍vector的3个数据结构:
- start:表示目前使用空间的头
- finish:表示目前使用空间的尾
- end_of_storage:表示目前可用空间的尾
- 说明:为了降低空间配置时的速度成本,vector实际配置的大小可能比客户端需求量更大一些,以备将来可能的扩充。这便是容量的概念。也就是说,一个vector的容量永远大于或等于其大小。一旦容量等于大小,下次再新增元素时就需要新开辟一块空间。如下图所示
- 运用start、finish、end_of_storage三个迭代器,vector提供了首尾标示、大小、容量、空容器判断、注标[]运算符、最前端元素值、最后端元素值....等机能,如下:
五、vector的构造与内存管理(constructor、push_back)
vector的内存管理
- vector默认使用alloc做为空间配置器,并据此另外定义了一个data_allocator,为的是更方便以元素大小为配置单位:
- 于是,data_allocator::allocate(n) 表示配置n个元素空间
构造函数
- vector提供许多构造函数,其中一个允许我们指定空间大小及初值:
push_back()函数
- 当我们以push_back() 将新元素安插入于vector尾端时,该函式首先检查是否还有备用空间,如果有就直接在备用空间上建构元素,并调整迭代器finish,使vector变大。如果没有备用空间了,就扩充空间(重新配置、搬移数据、释放原空间)
- push_back()原型如下:
六、vector内存重分配策略
- vector的内存重分配策略:
- vector是以数组的形式存储的,当往vector中增加元素时,如果vector的容量不足,那么vector就会进行扩容
- 扩容的规则是:并不是在原空间之后接续新空间(因为无法保证原空间之后尚有可供配置的空间),而是申请一块比现在大的新的内存空间(gcc和vc申请规则不同,见下面介绍),然后原来内存中的内容拷贝到新内存中,然后释放原来的内存
- 重点:在gcc和vc的环境下,vector的扩容规则是不一样的
- 注意(重点): 对vector 的任何操作,一旦引起空间重新配置,指向原vector的所有迭代器就都失效了。这是程序员易犯的一个错误,务需小心
Windows下
- vector内存重分配即容量的增长是有规律的,可以通过下面的公式描述:
maxSize = maxSize + ((maxSize >> 1) > 1 ? (maxSize >> 1) : 1)
- 图解:
- 就是由1、2、3、4、6、9、13、19......依次增长
- 从4之后开始有规则:当前索引处的值等于前一个元素值和前前前元素的值之和
- 测试程序如下:
- 运行效果如下:
Linux下
- Linux下的扩容规则是:其比较简单,就是将大小扩充为原来的2倍
maxSize = maxSize*2;
- 图解:就是由1、2、4、8、16......依次增长
- 测试程序如下:
- 运行效果如下:
七、vector的元素操作(pop_back、erase、clear、insert)
- 所提供的元素操作动作很多,不就在此文章中一一说明
pop_back
erase
- 下图是上面这个erase函数的版本
clear
insert
- 注意,插入完成后,新节点将位于哨兵迭代器(即上缪按的position,标示出插入点) 所指之节点的前方——这是STL对于“插入操作”的标准规范。下面的图片展示了insert(position,n,x)的操作
备用空间>=新增元素个数的情况:
- ①备用空间2>=新增元素个数2
- ②插入点之后的现有元素个数3>新增元素个数2
- ③插入点之后的现有元素个数2<=新增元素个数3
备用空间>=新增元素个数的情况:
- 例如下面备用空间2<新增元素个数n==3