Vector清空資料與釋放記憶體(.clear與.swap的區別與使用)

嚜寒發表於2016-04-18

0)簡單介紹

在vector的資料結構中,

.clear();清空資料

.size();當前vector容器記憶體儲的元素的個數

.capacity();當前vector容器重新分配記憶體之前所能容納的元素數量

.swap();函式交換


1)問題

在用vector做題時,輸入完一組資料處理完後,及時clear(),然後輸入下一組資料,但是如果在輸入之前,輸出之前vector所存的內容,會發現仍然存在,但是如果輸出.empty();它會返回1,告訴我們這個容器現在是空的,這是因為使用.clear()清空內容,但是沒有釋放記憶體的原因。舉例如下:

#include <iostream>
#include <vector>

using namespace std;
int main()
{
	vector <int >a;
	cout<<a.empty()<<endl;//輸出   1  代表該vector此時是空
	a.push_back(1);
	a.push_back(2);
	cout<<a[0]<<" "<<a[1]<<endl;//輸出1 2
	cout<<a.empty()<<endl;//輸出 0 代表該vector此時非空
	cout<<a.size()<<endl;//輸出2
	cout<<a.capacity()<<endl;//輸出2
	cout<<"***************"<<endl;

	//a[0]=NULL;a[1]=NULL; 這是賦值為0,並不清空資料,也不釋放記憶體。
	a.clear();
	cout<<a[0]<<" "<<a[1]<<endl;//仍然輸出1 2,因為沒有釋放記憶體,所以輸出該地址的內容仍然與之前一樣
	cout<<a.empty()<<endl;//輸出1  代表該vector此時已經為空
	cout<<a.size()<<endl;//輸出0,代表當前容器記憶體儲元素個數是0,與.empty()類似,都告訴我們當前容器是空的意思
	cout<<a.capacity()<<endl;//輸出2,代表當前該vector在重新分配儲存空間前所能容納的元素數量並沒有改變
	cout<<"***************"<<endl;

	/*
	下面這五行說明,.pop_back()與.clear()起到了相同的作用,都是清空資料,但是沒有釋放記憶體
	while(!a.empty()){
		a.pop_back();
	}
	cout<<a.empty()<<endl;//輸出 1 代表該vector此時已經為空
	cout<<a[0]<<" "<<a[1]<<endl;//仍然輸出為 1 2,因為沒有釋放記憶體,所以輸出該地址的內容仍然與之前一樣
	*/
	a.push_back(4);
	cout<<a[0]<<" "<<a[1]<<" "<<a[2]<<endl;//輸出 4 2 0   儘管沒有釋放記憶體,但是已經認為該vector已經被清空,所以再push_back();時,a[0]被覆蓋。
	cout<<a.size()<<endl;//輸出1,代表當前容器記憶體儲元素個數是1,就是剛剛push_back();裝進去的數起到的作用
	cout<<a.capacity()<<endl;//此時仍然輸出2
	cout<<"***************"<<endl;

	//那麼如何釋放記憶體呢?我們用swap交換到一個新的型別的vector,將原來的a拷貝出去,然後自然銷燬,而新的到的a是全新的沒有存任何資料的
	vector<int>().swap(a);
	//a.swap();
	cout<<a.size()<<endl;//輸出 0
	cout<<a.capacity()<<endl;.// 輸出 0
	//cout<<a[1]<<endl;

}


2)處理辦法

So,如果我們只是做題,.clear();就可以繼續輸入下一組資料了,儘管佔據的記憶體大小不一定是我們希望的大小(不是輸入新的資料後應該佔據的記憶體大小),但一般不會影響到做題。

如果我們想得到一個全新的該vector,那就用1)中code最後展示的一部分,用.swap();重新拷貝一個全新的vector,然後原有的vector會被自然銷燬。另一個解決方法就是在每一次重新輸入資料之前,我們都重新定義,當然這不是讓你在一個作用域內將同名函式重定義(會報錯),我們是指在比如for的每次迴圈的開頭重新定義,讓他們處在不同作用域,如下:

#include <iostream>
#include <vector>

using namespace std;
int main()
{
	int n=10;
	while(n--){
		vector <int >a;
		int k;
		cin>>k;
		for(int i=1;i<=k;i++){
			a.push_back(k);
		}
		cout<<a.capacity()<<endl;//如果k先後輸入 2 1 那麼我們輸出的vector佔據的記憶體大小先後輸出 2 1,這說明每一次都是一個全新的vector,當然如果你輸入更多的測試資料比如,8 7 6 5 4 3 2 1,你會發現一個有趣的現象,vector對應輸出的數是8 8 8 8 4 4 2 1,這是合理的,作業系統一課中曾經學到過這樣一個分配記憶體空間的辦法,就是每次分配的大小都介於2^n與2^(n+1)之間,這與vector分配空間有相通之處(參考下面的3))。
	}
}


3)關於vector儲存資料以及用.swap()釋放記憶體的原理解釋

vector由於是一個不定長儲存的資料結構,每一次分配的大小都是比面前輸入的資料個數略大一點(實際上也並不準確,參看2)code中註釋,是介於2^n與2^(n+1)之間),所以每一次push_back()且發現當被分配的儲存空間已裝滿資料時,都是將包含現有資料的vector進行拷貝,進入一個更大一點的vector,而原有的vector就會被自然銷燬,我們用.swap()釋放記憶體的原理其實是相似的,即手動進行了一次人工拷貝的操作。


相關文章