C vector的內部行為

2021-06-27 07:23:26 字數 2349 閱讀 6417

c++中的vector是乙個非常靈活的陣列,它可以自動擴充大小來容納新的元素,也可以快速地索引儲存的元素,然而,這種使用上的便捷也是有代價的,因為vector的底層資料結構確實是乙個陣列,只是封裝了一些便利的操作,像push_back()、reserve()等,下面我們就通過例子來看一下這些簡便操作背後的行為,為了說明問題,我們定義了乙個類,並在其建構函式中輸出一些資訊,類定義如下:

class a {

static int i;

public:

int id;

a() {

id = i++;

cout<<"a: constructor"<

vectorv1(2);

cout<<"id of the 1st element: "<

a: constructor

a: copy constructor

a: copy constructor

a: destructor

id of the 1st element: 1

id of the 2nd element: 2

a: destructor

a: destructor

可以看到,在定義v1的時候,總共呼叫了1次預設建構函式和2次拷貝建構函式,定義過後,v1中便已經儲存了2個物件,且它們的id分別為1、2,這說明v1中的2個物件是通過拷貝建構函式得到的,那麼拷貝的是誰呢?當然就是呼叫預設建構函式生成的那個臨時物件,這個臨時物件在定義完v1後就被析構了,所以在輸出id之前會先列印乙個析構函式被呼叫的訊息。接下來換一種定義方式:

vectorv1;

v1.reserve(2);

cout<<"id of the 1st element: "<

這裡通過reserve來為v1保留兩個物件的儲存空間,輸出結果如下:

id of the 1st element: 0

id of the 2nd element: 0

可以看到,在這種情況下,v1中不會自動構造並儲存2個物件,但是我們還能僥倖地對這兩個物件進行操作,儘管這兩個操作是毫無意義的。接下來看看reserve()是怎麼預留儲存空間的:

vectorv1(2);

v1.reserve(3);

輸出結果如下:

#1  a: constructor

#2  a: copy constructor

#3  a: copy constructor

#4  a: destructor

#5  a: copy constructor

#6  a: copy constructor

#7  a: destructor

#8  a: destructor

#9  a: destructor

#10  a: destructor

大家可以數數共呼叫了幾次建構函式,前三次建構函式在我們的預期之中,但是隨著reserve的呼叫,我們又呼叫了兩次拷貝建構函式,這是因為reserve為我們弄了個更大的陣列,並試圖把原陣列裡面的東西放到新陣列裡,之後便會刪掉原來的陣列,這一點也可以從#7、#8兩行的析構函式可以看出來(析構掉了原陣列裡的兩個物件),所以改變v1的大小並不像使用起來那麼簡單,有可能引發大量的構造析構操作。下面再來看乙個例子:

a a;

vectorv1;

v1.reserve(2);

v1.push_back(a);

v1.push_back(a);

v1.push_back(a);

在這個例子中,開始給v1預留了2個物件的空間,但隨後插入了3個物件,可以看看輸出結果是什麼:

a: constructor

a: copy constructor

a: copy constructor

a: copy constructor

a: copy constructor

a: copy constructor

a: destructor

a: destructor

a: destructor

a: destructor

a: destructor

a: destructor

可以看到,共呼叫了5個拷貝建構函式!前兩個好理解,是伴隨著前兩個push_back而被呼叫的,但是第三個push_back的時候,因為v1中的空間不夠,所以重新弄了個陣列,首先把原來陣列裡的兩個物件拷貝過來,然後才將第三個物件push進新陣列裡,所以第三個push_back引發了3個拷貝建構函式,當然同時也額外引發了兩個析構函式,所以vector雖然好用,但是某些時候可能引發大量的記憶體分配及構造析構操作,如果應用程式對這個敏感,就要考慮其他的容器了,像list。

Java內部類的弟弟行為

public outterclass private class innerclass2 public static void main string args 那麼,當內部類是private的時候,把內部類的成員修飾為private有什麼意義嗎?當我們不想讓外部類以外的區域訪問內部類時,可以將內部...

構造器內部的多型方法行為

package com.lu.test import static lu.utils.print.在任何構造器內部,整個物件可能只是部分形成 我們只知道基類物件已經進行初始化。如果構造器只是在構建物件過程中的乙個步驟,並且該物件所屬的類是從這個構造器所屬 的類匯出的,那麼匯出部分在當前構造器正在被呼...

構造器內部多型方法的行為

如果在超類的構建器中呼叫了子類覆蓋過的方法,則編譯器缺省會呼叫在超類構建的過程中呼叫已經被子類覆蓋過的方法,而不是超類中的原始方法。這種錯誤很難從邏輯上進行排查,所以一定要格外小心!以下是例子 class glyph glyph class roundglyph extends glyph void...