STL6大标准库的关系和作用
STL六大組件簡介
1、容器(Containers):各種數據結構,如Vector,List,Deque,Set,Map,用來存放數據,STL容器是一種Class Template,就體積而言,這一部分很像冰山載海面的比率。
2、算法(Algorithms):各種常用算法如Sort,Search,Copy,Erase,從實現的角度來看,STL算法是一種Function Templates。
3、迭代器(Iterators):扮演容器與算法之間的膠合劑,是所謂的“泛型指針”,共有五種類型,以及其它衍生變化,從實現的角度來看,迭代器是一種將:Operators*,Operator->,Operator++,Operator--等相關操作予以重載的Class Template。所有STL容器都附帶有自己專屬的迭代器——是的,只有容器設計者才知道如何遍歷自己的元素,原生指針(Native pointer)也是一種迭代器。
4、仿函數(Functors): 行為類似函數,可作為算法的某種策略(Policy),從實現的角度來看,仿函數是一種重載了Operator()的Class?或?Class Template。一般函數指針可視為狹義的仿函數。
5、配接器(適配器)(Adapters):一種用來修飾容器(Containers)或仿函數(Functors)或迭代器(Iterators)接口的東西,例如:STL提供的Queue和Stack,雖然看似容器,其實只能算是一種容器配接器,因為 它們的底部完全借助Deque,所有操作有底層的Deque供應。改變Functor接口者,稱為Function Adapter;改變Container接口者,稱為Container Adapter;改變Iterator接口者,稱為Iterator Adapter。配接器的實現技術很難一言蔽之,必須逐一分析。
6、分配器(Allocators):負責空間配置與管理,從實現的角度來看,配置器是一個實現了動態空間配置、空間管理、空間釋放的Class Template。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??——《STL源碼剖析》
這六大組件的交互關系:container(容器)?通過?allocator(配置器)?取得數據儲存空間,algorithm(算法)通過?iterator(迭代器)存取?container(容器)?內容,functor(仿函數)?可以協助?algorithm(算法)?完成不同的策略變化,adapter(配接器)?可以修飾或套接?functor(仿函數)。
一、STL簡介
(一)、泛型程序設計
泛型編程(generic programming)
將程序寫得盡可能通用
將算法從數據結構中抽象出來,成為通用的
C++的模板為泛型程序設計奠定了關鍵的基礎
(二)、什么是STL
1、STL(Standard Template Library),即標準模板庫,是一個高效的C++程序庫。
2、包含了諸多在計算機科學領域里常用的基本數據結構和基本算法。為廣大C++程序員們提供了一個可擴展的應用框架,高度體現了軟件的可復用性
3、從邏輯層次來看,在STL中體現了泛型化程序設計的思想(generic programming)
在這種思想里,大部分基本算法被抽象,被泛化,獨立于與之對應的數據結構,用于以相同或相近的方式處理各種不同情形。
4、從實現層次看,整個STL是以一種類型參數化(type parameterized)的方式實現的
基于模板(template)
二、STL組件
Container(容器) 各種基本數據結構
Adapter(適配器) 可改變containers、Iterators或Function object接口的一種組件
Algorithm(算法) 各種基本算法如sort、search…等
Iterator(迭代器) 連接containers和algorithms
Function object(函數對象)?
Allocator(分配器)
(一)、容器
容器類是容納、包含一組元素或元素集合的對象
七種基本容器:
向量(vector)、雙端隊列(deque)、列表(list)、集合(set)、多重集合(multiset)、映射(map)和多重映射(multimap)
標準容器的成員絕大部分都具有共同的名稱
序列式容器
序列式容器Sequence containers,其中每個元素均有固定位置——取決于插入時機和地點,和元素值無關。(vector、deque、list)
關聯式容器
關聯式容器Associative containers,元素位置取決于特定的排序準則以及元素值,和插入次序無關。(set、multiset、map、multimap)
1、需要頻繁在序列中間位置上進行插入和/或刪除操作且不需要過多地在序列內部進行長距離跳轉,應該選擇list
2、vector頭部與中間插入刪除效率較低,在尾部插入與刪除效率高。
3、deque是在頭部與尾部插入與刪除效率較高
set/map/multiset/multimap?
? ? set,同map一樣,所有元素都會根據元素的鍵值自動被排序,因為set/map兩者的所有各種操作,都只是轉而調用RB-tree的操作行為,不過,值得注意的是,兩者都不允許兩個元素有相同的鍵值。
? ? 不同的是:set的元素不像map那樣可以同時擁有實值(value)和鍵值(key),set元素同時擁有實值和鍵值,且實值就是鍵值,鍵值就是實值,而map的所有元素都是pair,同時擁有實值(value)和鍵值(key),pair的第一個元素被視為鍵值,第二個元素被視為實值。
? ? 至于multiset/multimap,他們的特性及用法和set/map完全相同,唯一的差別就在于它們允許鍵值重復,即所有的插入操作基于RB-tree的insert_equal()而非insert_unique()。In computer science, a multimap (sometimes also multihash) is a generalization of a map or associative array
abstract data type in which more than one value may be associated with and returned for a given key.
摘自 sgi stl 紅黑樹數據結構定義:
C++ Code?
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | typedef?bool?_Rb_tree_Color_type; const?_Rb_tree_Color_type?_S_rb_tree_red?=?false; const?_Rb_tree_Color_type?_S_rb_tree_black?=?true; ? struct?_Rb_tree_node_base { ??typedef?_Rb_tree_Color_type?_Color_type; ??typedef?_Rb_tree_node_base*?_Base_ptr; ? ??_Color_type?_M_color; ??_Base_ptr?_M_parent; ??_Base_ptr?_M_left; ??_Base_ptr?_M_right; ? ??static?_Base_ptr?_S_minimum(_Base_ptr?__x) ??{ ????while?(__x->_M_left?!=?0)?__x?=?__x->_M_left; ????return?__x; ??} ? ??static?_Base_ptr?_S_maximum(_Base_ptr?__x) ??{ ????while?(__x->_M_right?!=?0)?__x?=?__x->_M_right; ????return?__x; ??} }; ? template?<class?_Value> struct?_Rb_tree_node?:?public?_Rb_tree_node_base { ??typedef?_Rb_tree_node<_Value>*?_Link_type; ??_Value?_M_value_field; }; |
hash_set/hash_map/hash_multiset/hash_multimap
? ? hash_set/hash_map,兩者的一切操作都是基于hashtable之上。不同的是,hash_set同set一樣,同時擁有實值和鍵值,且實值就是鍵值,鍵值就是實值,而hash_map同map一樣,每一個元素同時擁有一個實值(value)和一個鍵值(key),所以其使用方式,和上面的map基本相同。但由于hash_set/hash_map都是基于hashtable之上,所以不具備自動排序功能。為什么? 因為hashtable沒有自動排序功能。
? ? 至于hash_multiset/hash_multimap的特性與上面的multiset/multimap完全相同,唯一的差別就是它們hash_multiset/hash_multimap的底層實現機制是hashtable(而multiset/multimap,上面說了,底層實現機制是RB-tree),所以它們的元素都不會被自動排序,不過也都允許鍵值重復。
? ? 所以說白了,什么樣的結構決定其什么樣的性質,因為set/map/multiset/multimap都是基于RB-tree之上,所以有自動排序功能,而hash_set/hash_map/hash_multiset/hash_multimap都是基于hashtable之上,所以不含有自動排序功能,至于加個前綴multi_無非就是允許鍵值重復而已。
std::tr1::unordered_map 是無序哈希表,但操作效率要比 std::map、std::hash_map、?__gnu_cxx::hash_map 都要高,可以研究一下。
(二)、迭代器
1、迭代器Iterators,用來在一個對象群集(collection of objects)的元素上進行遍歷。這個對象群集或許是個容器,或許是容器的一部分。迭代器的主要好處是,為所有容器提供了一組很小的公共接口。迭代器以++進行累進,以*進行提領,因而它類似于指針,我們可以把它視為一種smart pointer
2、比如++操作可以遍歷至群集內的下一個元素。至于如何做到,取決于容器內部的數據組織形式。
3、每種容器都提供了自己的迭代器,而這些迭代器能夠了解容器內部的數據結構。
(三)、算法
算法Algorithms,用來處理群集內的元素。它們可以出于不同的目的而搜尋、排序、修改、使用那些元素。通過迭代器的協助,我們可以只需編寫一次算法,就可以將它應用于任意容器,這是因為所有的容器迭代器都提供一致的接口。
(四)、適配器
1、適配器是一種接口類
為已有的類提供新的接口
目的是簡化、約束、使之安全、隱藏或者改變被修改類提供的服務集合
2、三種類型的適配器:
容器適配器:用來擴展7種基本容器,它們和順序容器相結合構成棧、隊列和優先隊列容器
迭代器適配器(反向迭代器、插入迭代器、IO流迭代器)
函數適配器(函數對象適配器、成員函數適配器、普通函數適配器)
(五)、函數對象
1、函數對象(function object)也稱為仿函數(functor)
2、一個行為類似函數的對象,它可以沒有參數,也可以帶有若干參數。
3、任何重載了調用運算符operator()的類的對象都滿足函數對象的特征
4、函數對象可以把它稱之為smart function。
5、STL中也定義了一些標準的函數對象,如果以功能劃分,可以分為算術運算、關系運算、邏輯運算三大類。為了調用這些標準函數對象,需要包含頭文件<functional>。
(六)、分配器
負責空間配置與管理。從實現的角度來看,配置器是一個實現了動態空間配置、空間管理、空間釋放的class template。
隱藏在這些容器后的內存管理工作是通過STL提供的一個默認的allocator實現的。當然,用戶也可以定制自己的allocator,只要實現allocator模板所定義的接口方法即可,然后通過將自定義的allocator作為模板參數傳遞給STL容器,創建一個使用自定義allocator的STL容器對象,如:
? ? stl::vector<int, UserDefinedAllocator> array;
? ? 大多數情況下,STL默認的allocator就已經足夠了。這個allocator是一個由兩級分配器構成的內存管理器,當申請的內存大小大于128byte時,就啟動第一級分配器通過malloc直接向系統的堆空間分配,如果申請的內存大小小于128byte時,就啟動第二級分配器,從一個預先分配好的內存池中取一塊內存交付給用戶,這個內存池由16個不同大小(8的倍數,8~128byte)的空閑列表組成,allocator會根據申請內存的大小(將這個大小round up成8的倍數)從對應的空閑塊列表取表頭塊給用戶。
這種做法有兩個優點:
? ?(1)小對象的快速分配。小對象是從內存池分配的,這個內存池是系統調用一次malloc分配一塊足夠大的區域給程序備用,當內存池耗盡時再向系統申請一塊新的區域,整個過程類似于批發和零售,起先是由allocator向總經商批發一定量的貨物,然后零售給用戶,與每次都向總經商要一個貨物再零售給用戶的過程相比,顯然是快捷了。當然,這里的一個問題時,內存池會帶來一些內存的浪費,比如當只需分配一個小對象時,為了這個小對象可能要申請一大塊的內存池,但這個浪費還是值得的,況且這種情況在實際應用中也并不多見。
? ?(2)避免了內存碎片的生成。程序中的小對象的分配極易造成內存碎片,給操作系統的內存管理帶來了很大壓力,系統中碎片的增多不但會影響內存分配的速度,而且會極大地降低內存的利用率。以內存池組織小對象的內存,從系統的角度看,只是一大塊內存池,看不到小對象內存的分配和釋放。
參考:
C++ primer 第四版
Effective C++ 3rd
C++編程規范
總結
以上是生活随笔為你收集整理的STL6大标准库的关系和作用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: int *ptr=(int *)(a+1
- 下一篇: 快速弄懂内存字节对齐