1. 程式人生 > 其它 >C++ vector.reserve方法作用

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 <iostream>
#include <vector>
using namespace std;

#define MAX_NUM 9

int main(){
	vector<int> 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 <iostream>
#include <vector>
using namespace std;

#define MAX_NUM 9

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

	vector<int>::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 <iostream>
#include <vector>
using namespace std;

#define MAX_NUM 8	//MAX_NUM修改為8,其餘地方不做任何修改

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

	vector<int>::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 <iostream>
#include <vector>
#include <stdint.h>
using namespace std;

void growPushBack(vector<int> &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<int> vecIntA;
	sz = vecIntA.capacity();
	//宣告vector後未使用reserve,直接進行push_back操作 
	cout << "Making vecIntA growing:" << endl;
	growPushBack(vecIntA, sz);
	
	cout << "\n========separator========\n" << endl;
	
	vector<int> 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不會自動分配空間。