C++ vector.reserve方法作用


1、vector中push_back操作

push_back的作用是在vector的末尾添加一个新元素。val的内容被复制(或移动)到新元素。
这有效地将容器大小增加1。当且仅当新的vector大小超过当前vector容量时,会重新自动分配新的存储空间。
Tips:

  • std::vector::size()
    vec.size()返回vec中元素的个数。
  • std::vector::capacity()
    vec.capacity()返回vec在内存中分配的空间大小。

push_back操作demo1:

//code1

#include 
#include 
using namespace std;

#define MAX_NUM 9

int main(){
	vector vecInt;
	
	for(int i = 0; i != MAX_NUM; i++){
		vecInt.push_back(i);
	}
	/**
	  some code
	*/
	vecInt.push_back(123);

	for(int i : vecInt){
		cout << i << " ";
	}
	
	return 0;
}
// 0 1 2 3 4 5 6 7 8 123

以上代码先声明了一个存放int类型的vector,然后把i递增push_back到vecInt中。之后再添加一个元素到123到vecInt中。

push_back操作demo2:
iterator遍历vector

//code2

#include 
#include 
using namespace std;

#define MAX_NUM 9

int main(){
	vector vecInt;
	
	for(int i = 0; i != MAX_NUM; i++){
		vecInt.push_back(i);
	}

	vector::iterator iter = vecInt.begin();
	cout << "the 1st element: " << *iter << endl;
	
	vecInt.push_back(123);
	
	while(iter != vecInt.end()){
		cout << *iter << " ";
		iter++;
	}
	
	return 0;
}
/*
the 1st element: 0
0 1 2 3 4 5 6 7 8 123
*/

在用for进行vector的push_back之后,初始化了一个iterator指向vecInt的begin位置,并打印验证。之后再用push_back在vector的末尾添加一个元素123,这时再用iter来遍历vecInt。

push_back操作demo3:
下面对MAX_NUM进行修改,将其改为8

//code3
#include 
#include 
using namespace std;

#define MAX_NUM 8	//MAX_NUM修改为8,其余地方不做任何修改

int main(){
	vector vecInt;
	
	for(int i = 0; i != MAX_NUM; i++){
		vecInt.push_back(i);
	}

	vector::iterator iter = vecInt.begin();
	cout << "the 1st element: " << *iter << endl;
	
	vecInt.push_back(123);
        cout <<"vecInt's capacity: " << vecInt.capacity() << endl;
	
	while(iter != vecInt.end()){
		cout << *iter << " ";
		iter++;
	}
	
	return 0;
}
/*
the 1st element: 0
vecInt's capacity: 16
-17891602 -17891602 -17891602 -17891602 -17891602 -17891602 -17891602 -17891602 -17891602 -17891602 -17891602 -17891602 -17891602 -17891602 -17891602 -17891602 -17891602 -17891602 -784369068 805499525 0 1 2 3 4 5 
6 7 123
*/

只修改了MAX_NUM的值,其他一致。再次运行程序时,程序异常。
原因分析
对于vector来说,和数组最大的区别之一就是不需要在初始化的时候声明vector的大小。如果初始化的时候没有指明vector的大小,那么会根据实际的使用情况,在内存中为vector分配的大小分别2->4->8->16...
当MAX_NUM是8时,在for循环进行push_back之后,vecInt在内存中的大小为8。对vecInt再次将123进行push_back的时候,新的vector大小将超过当前的vector大小,所以会自动重新分配存储空间。
由于vector的存储空间已经被重新分配,在push_back123之后iter自然也就指向一个未知的空间,所以程序异常。

2、 vector的reserve的作用

为避免vector中在push_back过程中会进行内存的自动重新分配问题,vector提供了reserve函数。
reserve的作用时更改vector的容量,使vector至少可以容纳n个元素。
如果n大于vector当前的容量,reserve会对vector进行扩容,且当push_back的元素数量大于n的时候,会重新分配一个大小为2n的新空间,再将原有的n的元素放入新开辟的内存空间中。其他情况下都不会重新分配vector的存储空间。
Demo:对比使用reserve的区别
说明:在main中声明了两个vector,vecInt为默认初始化,vecIntB使用capacity初始化其容量为100。分别对vetIntA和vecIntB进行同样的操作:
①把0~99依次push_back到vector中,
②在push_back的过程中观察vector的容量capacity是否发生变化。

#include 
#include 
#include 
using namespace std;

void growPushBack(vector &vec, uint16_t size){
	for(int i = 0; i < 100; i++){ 
		vec.push_back(i);
		if(size != vec.capacity()){
			size = vec.capacity();
			cout << "Capacity changed: " << size << endl;
		}
	}
}
int main(){
	uint16_t sz = 0;
	vector vecIntA;
	sz = vecIntA.capacity();
	//声明vector后未使用reserve,直接进行push_back操作 
	cout << "Making vecIntA growing:" << endl;
	growPushBack(vecIntA, sz);
	
	cout << "\n========separator========\n" << endl;
	
	vector vecIntB;
	sz = vecIntB.capacity();
	//声明vecIntB后用reserve来执行其容量为100 
	vecIntB.reserve(100); 
	cout << "Making vecIntB growing: " << endl;
	growPushBack(vecIntB, sz);
	
	return 0;
}
/*
Making vecIntA growing:
Capacity changed: 1
Capacity changed: 2
Capacity changed: 4
Capacity changed: 8
Capacity changed: 16
Capacity changed: 32
Capacity changed: 64
Capacity changed: 128

========separator========

Making vecIntB growing:
Capacity changed: 100
*/

Demo运行结果分析:
如果一个vector使用默认的capacity,那么在push_back操作的时候,会根据添加元素的数量,动态的自动分配空间,2^n递增;如果声明vector的时候,显式的使用capacity(size_type n)来指定vector的容量,那么在push_back的过程中(元素数量不超过n),vector不会自动分配空间。

相关