1. 程式人生 > >vector的size和capacity有什麼區別?

vector的size和capacity有什麼區別?

要說清這個問題,先丟擲另外一個問題:vector和普通的陣列有什麼區別?

你可能會說:大家都知道,vector是動態陣列~~

沒錯!  但是怎麼個動態法?怎麼實現的?

好,先說一下普通陣列,比如:int arr[10]或者int *arr = new int[10]; 其實是你到記憶體裡佔了10個int大小的地方(空間)

當然,你可以這樣操作:int a = arr[100];   arr[100] = 10;  這樣編譯器並不會報錯,最多會警告你----你有越界行為。

       也就是說,你一開始說好了,你只佔10個大小的地方,後來你出爾反爾,又去訪問或者操作第100個地方(為了說明問題,事實上是第101個),那麼記憶體的“管理員”他沒有不讓你操作的權利,只是給你出示了“黃牌警告”,告訴你:你去操作吧,出了問題概不負責!!!
       這就是陣列越界問題,越界會造成未知的問題(程式崩潰等等),即你寫的程式不受你控制了,或者不是你想要的結果(比如:你越界訪問的地方是別人的地方,如果別人也沒做“防護”,那麼你修改了那個地方的值,就會讓別人的會出現未知錯誤)。為了避免這個問題,那就老老實實的在那個10個大小的地方活動。

但是,在實際應用中,程式設計師的確有這樣的需求:我開始是分配了10個大小的地方,但是我想給它後面新增一個或者給中間某個位置插入一個,變成連續11個數值。

      我再描述一下這個需求:在一個連續的陣列新增元素,還能保證新的陣列仍然在記憶體連續,也就是說用下標可以訪問(arr[10]訪問第11個元素)。

 vector就實現了這樣的功能,當然vector功能不止這一個,還有很多操作(push_back,insert等)。

那麼,vector是怎麼實現這樣的功能的?可以參考《STL原始碼剖析》

我們以push_back()為例,

其中size就是實際存入資料空間的大小,capacity是容量,即能容納的資料個數。下面看一下push_back()的過程:

在insert_aux裡:

這個過程就是容量擴充(備用空間不夠了,就重新開闢更大的空間,把舊的拷貝進去,再把舊的釋放了,有了更大的新空間,就可以連續的插入和追加元素了

所以這個過程:重新配置->拷貝資料->釋放舊的空間

如果每新增一個元素都這樣操作,那效率太低了,索性一次多分分配些空間。

但是注意:

1.vector可以用下標訪問元素,但是,只能訪問size以內的(比如,size=10,capacity=15,就不能arr[12]這樣會報錯)

2.一旦擴容,原來空間就已經不存在了,陣列首地址也不存在了,因為舊的被複制到新的空間,舊的就被釋放了。

下面迴歸正題:size和capacity有什麼區別?

size是真實元素的所佔的空間開啟,capacity是整個可容納的空間大小;

如第一個圖:

size = finish - start

capacity = end_of_storage - start

下面看一下不同編譯器capacit大小分配情況:

這是vs2017的執行結果:

        vector<int> arr(10,1);//10個空間,初值都是1
	cout << "size=" << arr.size() << endl;
	cout << "capacity=" << arr.capacity() << endl;

	arr.push_back(2);//向後面新增一個元素2
	cout << "size=" << arr.size() << endl;
	cout << "capacity=" << arr.capacity() << endl;

這是ubantu16,g++ 5.4的執行結果:

為什麼一樣呢?

這個編譯器有關係,在《STL原始碼剖析》上可以找到答案:

但是再vs2017上,capacity在滿的時候,擴充的大小為原來的一半,而不是2倍。