1、基本概念
我们都知道c++原生的array是静态空间,一旦分配就不可更改,如果想要扩展大小就必须自行处理。vertor在提供array功能的基础上,帮我们完成空间的扩展,让我们使用起来更加的自由。
2、迭代器
vector提供的迭代器具备基本的算术运算,可随机访问vector内部的元素,因而属于随机迭代器。
3、容量扩展
当vector内部的空间已经使用完后,此时再向其中添加元素时,就需要扩展vector的容量。扩展容量时,需要进行以下三个步骤:
1. 分配一块新的内存,使其能够容纳包括新添加的元素在内的所有元素;
2. 将旧内存中的元素拷贝到新的内存中;
3. 将新添加的元素添加到新内存中;
4. 释放就内存。
由此可以看到,vector对空间进行扩展的代价是十分高的,如果我们每次扩展的时候容量只增加1,那么当vector使用空间已满后,每添加一个元素,就会引起一次容量扩展,这显示是不可接受的。STL标准设定的vector容量扩展系数为2,即每次扩展时,新的容量大小为当前容量大小的两倍。我们通过下面的测试代码进行验证一下:
vector<int> a;
a.push_back(1);
cout<<"size:"<<a.size()<<endl; //size:1
cout<<"capacity:"<<a.capacity()<<endl; //capacity:1
a.push_back(2);
cout<<"size:"<<a.size()<<endl; //size:2
cout<<"capacity:"<<a.capacity()<<endl; //capacity:2
a.push_back(3);
cout<<"size:"<<a.size()<<endl; //size:3
cout<<"capacity:"<<a.capacity()<<endl; //capacity:3
a.push_back(4);
cout<<"size:"<<a.size()<<endl; //size:4
cout<<"capacity:"<<a.capacity()<<endl; //capacity:4
a.push_back(5);
cout<<"size:"<<a.size()<<endl; //size:5
cout<<"capacity:"<<a.capacity()<<endl; //capacity:6
a.push_back(6);
cout<<"size:"<<a.size()<<endl; //size:6
cout<<"capacity:"<<a.capacity()<<endl; //capacity:6
通过上面的测试代码,你们一定很奇怪,根据log显示,容量的增长并不是按照两倍的速率进行。这里要说明的是STL是有多个实现版本的,不同版本的实现是不尽相同的,我测试使用的是vs2012,下面可以看下实现源码:
size_type _Grow_to(size_type _Count) const
{
// grow by 50% or at least to _Count
size_type _Capacity = capacity();
_Capacity = max_size() - _Capacity / 2 < _Capacity
? 0 : _Capacity + _Capacity / 2; // try to grow by 50%
if (_Capacity < _Count)
_Capacity = _Count;
return (_Capacity);
}
通过上面的代码,我们可以看到该版本的容量增长系数设定为1.5,而不是标准的2。这里知乎上的大神也有讨论过系数设定为多少才是最优的,我暂时还没弄懂,也不做讨论。但由此我们知道一点,当我们测试的结果跟一些教程的结果不一致时,先看看是不是STL的版本不同造成的。
4、内存释放
vector有提供自己的清理函数,但实际的内存是否真的释放了,需要先测试一下。看下下面的代码:
vector<int> a;
a.push_back(1);
cout<<"size:"<<a.size()<<endl; //size:1
cout<<"capacity:"<<a.capacity()<<endl; //capacity:1
a.push_back(2);
cout<<"size:"<<a.size()<<endl; //size:2
cout<<"capacity:"<<a.capacity()<<endl; //capacity:2
a.push_back(3);
cout<<"size:"<<a.size()<<endl; //size:3
cout<<"capacity:"<<a.capacity()<<endl; //capacity:3
a.push_back(4);
cout<<"size:"<<a.size()<<endl; //size:4
cout<<"capacity:"<<a.capacity()<<endl; //capacity:4
a.push_back(5);
cout<<"size:"<<a.size()<<endl; //size:5
cout<<"capacity:"<<a.capacity()<<endl; //capacity:6
a.push_back(6);
cout<<"size:"<<a.size()<<endl; //size:6
cout<<"capacity:"<<a.capacity()<<endl; //capacity:6
a.clear();
cout<<"size:"<<a.size()<<endl; //size:0
cout<<"capacity:"<<a.capacity()<<endl; //capacity:6
这里我们调用的clear函数,可以看到size为0,可容量还是6,证明内存并没有被释放,只是设定为未使用。如果想要真正释放内存,可以使用下面的方法:
vector<int>().swap(a);
cout<<"size:"<<a.size()<<endl; //size:0
cout<<"capacity:"<<a.capacity()<<endl; //capacity:0
这里我们使用一个空vector临时变量与a进行交换,导致a的容量变为0,而临时变量获取了a的内存,在作用域结束后就被系统回收了,从而间接达到释放a所使用的内存的目的。
5、特殊情况
vector是一个模板类,理论上是可以设定vector,但是vector涉及一下两个问题:
1. vector并不是一个容器;
2. vector并不保存bool类型的值,而是使用bit以节省空间。