《STL原始碼剖析》 序列式容器

2022-09-07 17:54:16 字數 3764 閱讀 4864

《stl原始碼剖析》

前言:  

所謂的序列式容器,其中的元素都可序,但未必有序,c++本身提供了乙個序列式容器array,stl 提供了vector, list, deque, srack, queue, priority-queue等

一. 使用reverse()函式提前設定容量大小

1.1 提前設定的原因-

對於vector和string,如果需要更多的記憶體空間,就會以類似realloc的思想來增長大小。vector容器支援隨機訪問,因此為了提高效率,它內部是使用動態陣列的方式實現的

在通過reverse()函式來申請特定大小的記憶體空間時總是按指數邊界來增大其內部緩衝區;當執行insert或push_back等增加元素的操作時,如果此時動態陣列的記憶體不夠用,就要重新分配記憶體,再把原陣列的內容複製過來,所以其訪問速度與一般的陣列相比,只有發生重新分配記憶體時,其效能才會下降

因此如果需要對大量的資料進行push_back操作,應當使用reverse()函式提前設定其容量大小,否則會出現許多次記憶體分配,造成效率低下

1.2 提前設定的原因 

1 vectorv;

2for (int i = 1; i <= 1000; ++i) v.push_back(i);

在大多數stl實現中,這段**在迴圈過程中將會導致2~10次的重新分配,然後我們把**改用reverse:

1 vectorv;

2 v.reverse(1000);3

for (int i = 1; i <= 1000; ++i) v.push_back(i);

二. 原始碼解析

vector 提供了許多constructors,其中乙個允許我們指定空間大小與初值:

1 vector(size_type __n, const _tp&__value,

2 const allocator_type& __a =allocator_type())

3: _base(__n, __a)

4 56

//上面 uninitialized_fill_n 這個函式,藏得很深在stl_uninitialized.h裡面,實際該函式還是對fill函式的一次封裝7//

最終呼叫的是fill函式,在 stl_alogbase.h 這個標頭檔案下面,如下,8//

不過這個資料夾下面有很多fill函式,我想應該是uninitialized_fill_n的作用還包括型別判斷,根據型別不同呼叫不同的fill函式

910 void fill(_forwarditer __first, _forwarditer __last, const _tp&__value)

我們以 push_back() 函式將新元素插入vector尾端時,該函式首先檢查是否還有備用空間,如果有則直接在備用空間上構造元素,並調整迭代器finish,使得vector變大。如果沒有備用空間就擴充:

1  void push_back(const _tp&__x) 

6else

7 _m_insert_aux(end(), __x);  //

重新構造整個vector並插入元素8}

9//表示不懂為啥要過載一次push_back()。。。

10void push_back()

15else

16_m_insert_aux(end());

17 }

至於 _m_insert_aux 函式,

1 vector<_tp _alloc>::_m_insert_aux(iterator __position, const _tp&__x)212

else

//無備用空間

1331

__stl_unwind((destroy(__new_start,__new_finish),

32_m_deallocate(__new_start,__len)));

33//

銷毀,釋放原vector

34destroy(begin(), end());

35 _m_deallocate(_m_start, _m_end_of_storage -_m_start);

36//

調整迭代器,指向新的vector

37 _m_start =__new_start;

38 _m_finish =__new_finish;

39 _m_end_of_storage = __new_start +__len;40}

41 }

三.  vector  的元素操作:pop_back, erase, clear, insert

3.1 ease() 函式作用是清除某乙個元素,或者清除兩個迭代器之間的所有元素,如下:

1

//清除某乙個元素

2iterator erase(iterator __position) 310

//清除迭代器__first 和 __last之間的所有元素

11iterator erase(iterator __first, iterator __last)

12

第二個 erase 示意圖如下:

3.2 insert函式是把元素插入到對應位置,該函式效率很低,特別是front插入,要移動所有元素退後乙個位置,很花銷時間,企業級資料盡量少用 vector 的 insert,以下是其源**:

1 template 2 void vector<_tp _alloc>::_m_fill_insert(iterator __position, size_type __n, 

3 const _tp&__x)424

else

2532

33//

不明白為什麼要比較__elems_after 和 _n,不是能夠全體移動並且直接插入要插入的元素嗎?所以

34//

感覺特別複雜,個人覺得可以改成:

35 uninitialized_copy(__position, _m_finish, __position +n);

36 _m_finish +=__n;

37 fill(__position, __position +__n, __x_copy);38}

39else

4058

__stl_unwind((destroy(__new_start,__new_finish);

59//

以下清除並且釋放舊的vector

60_m_deallocate(__new_start,__len)));

61destroy(_m_start, _m_finish);

62 _m_deallocate(_m_start, _m_end_of_storage -_m_start);

63//

移動起始點和水位

64 _m_start =__new_start;

65 _m_finish =__new_finish;

66 _m_end_of_storage = __new_start +__len;67}

68}69 }

STL原始碼剖析之序列式容器

最近由於找工作需要,準備深入學習一下stl原始碼,我看的是侯捷所著的 stl原始碼剖析 之所以看這本書主要是由於我過去曾經接觸過一些台灣人,我一直覺得台灣人非常不錯 這裡不涉及任何政治,僅限個人感受 在技術上他們比較嚴謹,在為人處世上也非常謙虛,所以一些台灣的技術資料我覺得是值得一看的。想要學習st...

《STL原始碼剖析》 序列式容器(二)list容器

list概述 相較於vector的連續線性空間,list就有點複雜了,但複雜有複雜的好處,每次插入或刪除乙個元素,就配置或釋放乙個元素。因此list不存在浪費空間的問題。而且對於任何位置插入或釋放元素,時間是常值。list的迭代器 首先list的節點 node 是乙個雙向鍊錶。另外list不能像ve...

STL原始碼剖析 序列式容器之deque

deque概述 deque是一種雙開口的連續線性空間,可以在頭尾兩端分別做元素的插入和刪除操作 deque沒有容量的概念,它是動態地以分段連續空間組合而成,隨時可以增加一段新的空間並鏈結起來 deque的中控器 deque由一段一段的定量連續空間構成 一旦有必要在deque前端或尾端增加新空間,便配...