vector是STL里常见的容器,虽然和数组一样是顺序容器,但是它可以随着元素的插入不断地扩增自己的容量

vector扩增容量的机制

先看代码
代码中的size()返回vector的大小(也就是目前有多少个元素),而capacity()则返回容器的容量(再次扩容前最多可以容纳的元素个数)

#include <iostream>
#include <vector>
using namespace std;
int main()
{
	vector<int> a = { 1,2,3,4,5,6,7,8,9 };
	cout << a.size() << endl;
	cout << a.capacity() << endl;
	a.push_back(0);
	cout << a.size() << endl;
	cout << a.capacity() << endl;
}

结果为(前两行为扩容前)

vs2019

容器的swap 容器的容积_容器的swap


devcpp

容器的swap 容器的容积_迭代器_02


可以看见原来有9个元素的vector大小(size)容量(capacity)都为9,那么说明目前这个vector已经满了,如果我们执行a.push_back(0);(在尾部插入一个整型0)那么vector就需要进行扩容,从结果的后两行可以看出,vector的容量都变大了,devcpp的容量翻倍,而vs2019增加了4(一般vector扩容会申请比原来容量多一倍的空间,就和devcpp一样,但是我也不知道为什么vs2019不是,可能它是内存管理大师吧。。。)

而vector的扩容并非简单的在容器尾部申请空间然后存储新的元素,vector的扩容是会申请一个新的空间,然后把原有的元素拷贝过去,再释放掉原有的空间。

#include <iostream>
#include <vector>
using namespace std;
int main()
{
	vector<int> a = { 1,2,3,4,5,6,7 };
	int* p = &a[0];
	a.push_back(8);
	int* q = &a[0];
	cout << "扩容前:" << p << endl;
	cout << "扩容后:" << q << endl;
}

结果为

容器的swap 容器的容积_#include_03


由此可见容器的首元素地址不一样了,容器整体搬家了

转载:vector的数据结构

vector数据结构,采用的是连续的线性空间,属于线性存储。他采用3个迭代器_First、_Last、_End来指向分配来的线性空间的不同范围,下面是声明3个迭代器变量的源代码。

template<class _Ty, class _A= allocator< _Ty> > 
class vector{ 
    ... 
    protected: 
    iterator _First, _Last, _End; 
};

_First指向使用空间的头部,_Last指向使用空间大小(size)的尾部,_End指向使用空间容量(capacity)的尾部。例如

int data[6]={3,5,7,9,2,4}; 
vector<int> vdata(data, data+6); 
vdata.push_back(6); 
...

vector初始化时,申请的空间大小为6,存放下了data中的6个元素。当向vdata中插入第7个元素“6”时,vector利用自己的扩充机制重新申请空间,数据存放

结构如图1所示:

容器的swap 容器的容积_容器的swap_04


简单描述一下。当插入第7个元素“6”时,vector发现自己的空间不够了,于是申请新的大小为12的内存空间(自增一倍),并将前面已有数据复制到

新空间的前部,然后插入第7个元素。此时_Last迭代器指向最后一个有效元素,而_End迭代器指向vector的最后有效空间位置。我们利用vector的成员函数size

可以获得当前vector的大小,此时为7;利用capacity成员函数获取当前vector的容量,此时为12。

转载于:

迭代器iterator的使用

既然vector在插入元素时会扩容,扩容就会改变自身数据的地址,那么在使用iterator需要特别小心,否则就会产生严重错误

#include <iostream>
#include <vector>
using namespace std;
int main()
{
	vector<int> a = { 5,6,7,8 };
	for (vector<int>::iterator i=a.begin();i<a.end();++i)
	{
		int j;
		cin >> j;
		a.push_back(j);
	}
	return 0;
}

这段代码在devcpp能过编译且能正常输入并结束程序,而vs2019则会引发错误

这段代码根本就是错的,我们来理解一下这段代码

(有的人可能会想,是不是因为我们一直在插入元素导致i不能和尾部指针相遇导致程序陷入死循环,并不是陷入死循环的问题,就算是,我们也可以用ctrl+Z关闭cin,不让容器插入元素来结束程序)

一开始for循环里定义了一个迭代器i,它指向容器里的第一个元素,也就是5,循环判断条件是i<a.end()(.end()表示容器最后一个元素的下一个地址)图中黄块8的右边白块,.end()返回它的地址,.begin()返回黄块5的地址

容器的swap 容器的容积_ci_05


循环改变条件是++i,也就是每次迭代器向右移动一位,而前文我们可以知道,创建好的vector容器一开始就是满的,在第一次插入时就需要扩容,扩容就导致原有的容器元素集体搬家(在内存中的地址集体改变),其中.end()返回的地址也会改变,这也就导致了个问题:

我们一开始定义的,i=a.begin(),没有改变,还停留在原来的地方,所以想要通过++i来结束循环几乎是不可能的

为了防止程序员犯错,c++引出了一个机制:

迭代器失效

容器扩容后原先定义的迭代器都会失效,使用迭代器必须重新定义(在循环中使用的容器必须特别注意迭代器失效的问题)