在完成了STL與泛型編程第一周的學習之后,有一些總結和心得在這里通過學習筆記的方式分享出來,筆記我是跟著老師在視頻中所講的內容按照順序記錄的,也不能說是流水賬,對課程中的一些問題還是添加了自己的理解和分析,供也在學習C++的小伙伴用作學習交流,如有理解不到位的地方,歡迎批評指正。
上周對于STL,老師做了一個大概的介紹,本周接著上周的內容繼續學習了分配器以及各類容器的結構與分類。
一.OOP與GP的區別
OOP(Object-Oriented programming)企圖將datas和methods關聯在一起
GP(Generic Programming)卻是將datas和methods分開來,如下圖所示:
采用GP,Containerns和Algorithms兩個團隊可以閉門造車,其間以Iterator溝通即可。Algorithms通過Iterators確定操作范圍,并通過Iterators取用Container中的元素。
二.特化(Specialization)和偏特化(Partial Specialization)
C++源碼中運用了大量的操作符重載(Operator Overloading)以及模板(Templates),操作符重載的相關規則這里就不再贅述,模板的運用分為類模板(Class Templates)、函數模板(Function Templates)和成員模板(Member Templates),之前的課程有詳細講過,老師也進行了復習,這里也不再贅述。
我的理解是,特化就是泛化的反面,常規的模板都是泛化的,所謂特化,就是當模板替代類型中的一個類型有它特有的處理方法時,我們可以將template< >中的內容抽離出來,即為這個類型定義它特有的方法,如下代碼所示:
偏特化分為個數上的偏和范圍上的偏。
個數上的偏很好理解,就是具有多個模板參數時,將一部分模板參數特化,其他模板參數保持泛化,如下代碼所示:
這里值得注意的是,特化部分參數只能從左至右特化,也就是說,不能第一個模板參數泛化,而將第二個模板參數特化。
我理解的范圍上的偏就是模板參數的類型是一個指針,那么模板參數所代表的類型就是這個指針所指向的類型。如下代碼所示:
這里值得注意的是,該指針指向什么由程序員自己定義。
三.分配器(allocators)
分配器最重要的兩個函數:allocate()和deallocate()
VC6所附的標準庫,其分配器的實現只是以::operator new()和::operator delete()來完成allocate()和deallocate(),并沒有任何特殊的設計。
而operator new()和operator delete()本質上還是調用基本的內存分配函數malloc()和內存釋放函數free():
BC++與VC6一樣,最終還是調用malloc()和free(),并且也是分配512ints,但是分配多少內存就要還多少內存,因此其接口設計非常不利于直接使用。
G2.9并沒用使用分配器allocator,而創造了另一個分配器alloc,
alloc的實現如下圖所示:
用鏈表的方式來分配內存,盡量減少調用malloc的次數,這樣程序運行效率更高,節省了額外的開銷。
但是之后的G4.9并沒有使用這種高效率的alloc分配器(原因不得而知),而是改用了new_allocator分配器,這又與之前提到的VC/BC一致了,本質上還是調用malloc和free。但是G4.9所附的標準庫中,有許多extention allocators,其中_pool_alloc就是G2.9中的alloc
四.容器——結構與分類
先來一張老師整理出的各種容器類型和所占字節數的圖:
1.容器list
List其實是一個環狀雙向鏈表,用雙向指針串起來,如下圖所示:
List的iterator是一個類,G2.9中,這個類與list是包含關系。
這里值得注意的是,除了array和vector之外,所有容器的iterator都必須是class
之前說到過GP的好處就是將data和algorithm分開,那么iterator就是它們之間的橋梁,算法提出的問題,iterator要必須都能回答,這是iterator必須遵循的原則。
Iterators的五個associated types:
①Iterator_category()分類
②Difference_type()距離
③Value_type()指向值的類型
④Reference
⑤Pointer
后面兩個目前還未使用。
萃取機(Iterator Traits)用以分離class iterators(直接問)和non-class iterators(間接問)
加入中間層traits,利用偏特化回答non-class類型
2.容器vector
Vector是一種單向開口先進后出的容器,它所占用的是連續內存空間,因此它不能原地擴充,一旦空間不夠,它必須尋找新的空間擴充,并且二倍增長,整個搬離到新開辟的兩倍空間。
Vector靠3根指針控制整個容器:
因其是占用連續內存空間,所以它的iterator不必設計成class
3.容器array
Arry跟vector一樣,也是占用連續的內存空間,其iterator是native pointer
4.容器forward_list
Forward_list是一種線狀單向串列,與雙向鏈表list差不多