對vector內部結構的解析(二)

2021-07-05 09:48:10 字數 1807 閱讀 5638

allocatorsa;   //將該模板類例項化為string型別

string * p = sa.allocate(5); //分配足以儲存5個string型別的空間卻不構造string , 返回指標

string * q = p; //另乙個指標

for( ; q != p + 5 ; q++)

for(string * ps = p ; ps != q ; ps++)

for( ; q != p ; q--)

sa.deallocate(p , 5); //**5個string的空間

列印出5行 「it ' s a test."

這個例子就能夠告訴我們allocator這個類的基本原理 , 它能夠分配足夠的記憶體用於儲存程式設計師指定數量的物件 , 卻不會呼叫建構函式 , 即在構造這個物件之前該位置的內容是未定義的 , 呼叫construct構造物件後再呼叫destroy就能銷毀物件 , 最後的deallocate是用來**空間的。

為什麼要在這裡說這個呢 , 其實vector內部就是這樣分配的 , vector內部有三個指標(型別為用來例項化的指定型別) ,其實就是我們所說的迭代器 , 第乙個指標名為start , 儲存了順序表的第乙個元素的起始位址 。 第二個指標名為finish , 儲存的是已經構造的最後乙個元素的下乙個位址 。第三個指標名為end_of_storage , 儲存的是已分配的空間的末尾的下乙個位址 , 用一張圖來看(數字表示已經構造的物件)

現在講一下vector是如何動態增長的 , 當我們在push_back新物件時 , 如果size() 等於capacity()  , 說明分配的物件空間已經用完 , 這是vector會要求記憶體分配一塊比原來大兩倍的空間給它(使用allocate分配 , 再把原來的資料拷貝或移動進去 , 再把舊空間用deallocate**) , 注意新分配的空間絕不一定是end_of_storage接下來的空間 , 這點一定要注意。

為什麼插入物件會消耗那麼多時間(見第一篇) , 這是因為vector是順序線性表結構 , 當在中間插入乙個元素時 , 它就必須把後面的所有元素都向後移一位 , 給插如的元素留出位置 , 並不破壞線性順序結構 , 請看下圖示意:

移位的操作可能會先呼叫用乙個臨時量儲存物件 , 然後再呼叫destroy , 最後再呼叫construct , 這是乙個很繁瑣也很染費時間的過程 , 尤其是元素越多越浪費時間 , 插入的位置越前也越浪費時間 , 所以在vector中盡量不要用插入操作。

至於迭代器實際上就是返回start和finish指標 , 因為vector本身是線性順序表 , 元素全是乙個接乙個排列的 , 所以迭代器不需要過載++和--等符號 , 因為下乙個位址一定就是需要的記憶體位置 。

而對於erase操作 , 比較類似於insert , 實際上就是呼叫destroy把元素銷毀 , 如果是最後乙個元素 , 則erase效率會很高 , 但如果要銷毀的元素在中間 , 那又是一件很麻煩的事情 , 因為erase後會出現乙個空格  , 所以要把後面的所有元素都移上來 , 原理與插入是一樣的。

而上文最後介紹的resize則是乙個判斷 , 當要求保留大於現有個數時 , 呼叫construct(如果大於容量則先分配)構造多出來的對像 , 反之呼叫destroy銷毀物件。

二,String型別內部結構剖析

原形 class string 普通建構函式 string string const char str else string的析構函式 string string void 拷貝建構函式 string string const string other 得分點 輸入引數為const型 賦值函式 s...

ios 類的內部結構

1.class 和 object 的定義 an opaque type that represents an objective c class.typedefstructobjc class class represents an instance of a class.structobjc ob...

block 塊的內部結構

每個oc物件都佔據著某個記憶體區域,因為例項變數的個數及物件所包含的關聯資料互不相同,所以每個物件所佔的記憶體區域大小也是有大有小,塊本身也是物件,在存放塊物件的記憶體區域中,首個變數是指向class物件的指標,該指標叫做isa。其餘記憶體裡含有塊丟向正常運轉所需的各種資訊。如下 塊 void is...