[转载]《STL源码剖析》阅读笔记之 迭代器及traits编程技法
?? 本文從三方面總結(jié)迭代器
?
一 迭代器思想
??? 迭代器的主要思想源于迭代器模式,其定義如下:提供一種方法,使之能夠依序巡防某個(gè)聚合物(容
器)所含的元素,而又無(wú)需暴露該聚合物的內(nèi)部表達(dá)式。可見(jiàn)她的主要作用便是能夠降低耦合,提高代碼的
模塊性。
????STL的的中心思想在于:將數(shù)據(jù)容器和算法分開(kāi),彼此獨(dú)立設(shè)計(jì),最后再以一貼膠著劑將它們撮合
在一起,這貼膠著劑便是迭代器。迭代器的行為類(lèi)似智能指針(例如標(biāo)準(zhǔn)庫(kù)的auto_ptr和boost庫(kù)的shared
_ptr),換句話說(shuō)它重載了* 和 –> 運(yùn)算符,由于設(shè)計(jì)一個(gè)適用于所有容器的迭代器是非常困難的,每個(gè)
迭代器都必須很了解容器,所以STL的每一種容器都提供了相應(yīng)的專(zhuān)屬迭代器。
??? STL在廣義上有5種迭代器類(lèi)型(不限于這5種,還可以是原生指針等,具體的容器定義自己的迭代器但
是類(lèi)型是這幾種之一或者是原生指針等)
- ???input iterator?: 這種迭代器所指對(duì)象不允許外界改變,即是只讀的
- ???output iterator?: 唯寫(xiě)
- ? ?forward iterator?: 允許寫(xiě)入型算法
- ???bidirectional iterator?: 可雙向移動(dòng)的迭代器
- ???random access iterator?:? 涵蓋所有指針運(yùn)算能力,可隨機(jī)訪問(wèn)任何位
??? 它們?cè)赟TL中的定義如下:
template <class T, class Distance> struct input_iterator {typedef input_iterator_tag iterator_category;typedef T value_type;typedef Distance difference_type;typedef T* pointer;typedef T& reference; }; struct output_iterator {typedef output_iterator_tag iterator_category;typedef void value_type;typedef void difference_type;typedef void pointer;typedef void reference; }; template <class T, class Distance> struct forward_iterator {typedef forward_iterator_tag iterator_category;typedef T value_type;typedef Distance difference_type;typedef T* pointer;typedef T& reference; }; template <class T, class Distance> struct bidirectional_iterator {typedef bidirectional_iterator_tag iterator_category;typedef T value_type;typedef Distance difference_type;typedef T* pointer;typedef T& reference; }; template <class T, class Distance> struct random_access_iterator {typedef random_access_iterator_tag iterator_category;typedef T value_type;typedef Distance difference_type;typedef T* pointer;typedef T& reference; };?
二 迭代器相應(yīng)型別及traits思想
??? 書(shū)中把traits技法稱(chēng)為STL源代碼的門(mén)鑰,可見(jiàn)其十分重要。先介紹迭代器相應(yīng)型別,從字面上意義來(lái)
說(shuō)便是和迭代器相關(guān)的類(lèi)型信息,實(shí)際上有5種常用的迭代器類(lèi)型:
- ????value type?: 迭代器所指對(duì)象的型別
- ????difference type?: 迭代器之間的距離型別
- ????reference type?: 迭代器引用型別
- ????pointer type?: 迭代器指針型別
- ????iterator_category?: 迭代器本身的型別
??? STL內(nèi)部需要知道當(dāng)前的迭代器的這些型別信息,其所使用的方法主要是模板的參數(shù)推導(dǎo)、模板內(nèi)嵌型
別以及模板偏特化。這里介紹下模板偏特化的概念。
模板的偏特化是指任何template參數(shù)更進(jìn)一步的條件限制所設(shè)計(jì)出來(lái)的一個(gè)特化版本,例如
template<typename T>
class C{…}???? //這個(gè)版本允許T為任何類(lèi)型
?
template<typename T>
class C<T*>{…} //這個(gè)特化版本僅適用于“T為原生指針的”的情況,它比上面的更特殊
?????有了模板偏特化,就可以讓traits萃取出原生指針(譬如vector的迭代器就是原生指針型別的)以及指
向常量的原生指針型別而不僅僅是類(lèi)類(lèi)型的,而負(fù)責(zé)萃取的便是?iterator_traits:
template <class Iterator> struct iterator_traits {typedef typename Iterator::iterator_category iterator_category;typedef typename Iterator::value_type value_type;typedef typename Iterator::difference_type difference_type;typedef typename Iterator::pointer pointer;typedef typename Iterator::reference reference; };??? 如果是類(lèi)類(lèi)型的性別,用上面這個(gè)就可以獲得其5個(gè)相應(yīng)型別,當(dāng)然這些型別必須都在相應(yīng)iterator類(lèi)
里面定義好(見(jiàn)第一節(jié)的5種迭代器的定義),那么如果不是上面5種而是原生指針等其他型別呢?這時(shí)候
就用到了模板偏特化:
//原生指針用這個(gè) template <class T> struct iterator_traits<T*> {typedef random_access_iterator_tag iterator_category;typedef T value_type;typedef ptrdiff_t difference_type;typedef T* pointer;typedef T& reference; }; //指向常量的原生指針用這個(gè) template <class T> struct iterator_traits<const T*> {typedef random_access_iterator_tag iterator_category;typedef T value_type;typedef ptrdiff_t difference_type;typedef const T* pointer;typedef const T& reference; };??? 通過(guò)這個(gè)traits我們就可以獲得任何一種iterator的相應(yīng)型別,通過(guò)以下表達(dá)式即可:
??? iterator_traits<…>::…
??? 說(shuō)到這里有一個(gè)很重要是設(shè)計(jì)思想不得不提,就是通過(guò)函數(shù)重載在編譯時(shí)決策正確的函數(shù)調(diào)用。這個(gè)問(wèn)
題源于5種迭代器的類(lèi)型,它們的巡防能力是不同的,例如random acess iterator是巡防能力最強(qiáng)的,可以
在O(1)時(shí)間巡防指定位置,而這個(gè)用其他的迭代器可能需要O(n)。所以為了提高效率,我們應(yīng)該用和迭代器
類(lèi)型最匹配的算法函數(shù)去調(diào)用,能用random access iterator的就不要用其他的。那么怎么做呢?
- ??? 首先通過(guò)traits獲得iterator_category,這樣我們能夠知道當(dāng)前迭代器的類(lèi)型。實(shí)際上iterator_category就是用來(lái)提供這種服務(wù)的。
- ??? 在函數(shù)調(diào)用時(shí)生成相應(yīng)迭代器類(lèi)型的臨時(shí)對(duì)象作為實(shí)參傳遞,編譯器就會(huì)調(diào)用相應(yīng)的重載函數(shù)。
??? 為了重載函數(shù)識(shí)別,我們有對(duì)應(yīng)的5種迭代器標(biāo)識(shí)類(lèi):
struct input_iterator_tag {}; struct output_iterator_tag {}; struct forward_iterator_tag : public input_iterator_tag {}; struct bidirectional_iterator_tag : public forward_iterator_tag {}; struct random_access_iterator_tag : public bidirectional_iterator_tag {}; 繼承是為了可以使用傳遞調(diào)用,當(dāng)不存在某種迭代器類(lèi)型匹配時(shí)編譯器會(huì)依據(jù)繼承層次向上查找進(jìn)行傳遞。 以distance為例: //這里category()就是為了產(chǎn)生臨時(shí)對(duì)象 template <class InputIterator> inline iterator_traits<InputIterator>::difference_type distance(InputIterator first, InputIterator last) {typedef typename iterator_traits<InputIterator>::iterator_category category;return __distance(first, last, category()); } //input iterator 版,注意函數(shù)形參最后的類(lèi)型 template <class InputIterator> inline iterator_traits<InputIterator>::difference_type __distance(InputIterator first, InputIterator last, input_iterator_tag) {iterator_traits<InputIterator>::difference_type n = 0;while (first != last) {++first; ++n;}return n; } //random access iterator 版 template <class RandomAccessIterator> inline iterator_traits<RandomAccessIterator>::difference_type __distance(RandomAccessIterator first, RandomAccessIterator last,random_access_iterator_tag) {return last - first; }三?__type_traits思想
??? 有了前面的基礎(chǔ),我們理解到STL是非常重視效率的,而SGI STL又在其基礎(chǔ)上實(shí)現(xiàn)了一個(gè)
__type_traits,根據(jù)前面的經(jīng)驗(yàn)我們知道它是一個(gè)萃取劑,只不過(guò)它萃取的型別是:
- ??? 是否具備non-trivial default ctor?
- ??? 是否具備non-trivial copy ctor?
- ??? 是否具備non-trivial assignment operator?
- ??? 是否具備non-trivial dtor?
??? 這里的non-trivial意指非默認(rèn)的相應(yīng)函數(shù),我們知道編譯器會(huì)為每個(gè)類(lèi)構(gòu)造以上四種默認(rèn)的函數(shù),如
果沒(méi)有定義自己的,就會(huì)用編譯器默認(rèn)函數(shù),如果使用默認(rèn)的函數(shù),本來(lái)就是按位拷貝我們可以使用memcpy
等函數(shù)來(lái)加快速度,提高效率。
??? 為了使用函數(shù)重載決議,我們使用類(lèi)類(lèi)型來(lái)定義兩種類(lèi)型,__true_type和__false_type
struct __true_type { }; struct __false_type { }; template <class type> struct __type_traits { typedef __true_type this_dummy_member_must_be_first;typedef __false_type has_trivial_default_constructor;typedef __false_type has_trivial_copy_constructor;typedef __false_type has_trivial_assignment_operator;typedef __false_type has_trivial_destructor;typedef __false_type is_POD_type; }; 這個(gè)是泛化版,STL對(duì)幾乎每種內(nèi)置類(lèi)型都定義了相應(yīng)的特化版本來(lái)制定它們的類(lèi)型,整體實(shí)現(xiàn)不難。 ? 后記: 通過(guò)迭代器的設(shè)計(jì),我們能夠看到很多非常有價(jià)值的思想,也對(duì)模板的強(qiáng)大有了更加深刻的認(rèn)識(shí),這些也是 繼續(xù)閱讀STL源碼的基礎(chǔ)。轉(zhuǎn)載地址:http://www.cnblogs.com/HappyAngel/archive/2011/04/19/2021413.html
轉(zhuǎn)載于:https://www.cnblogs.com/HXloveLL/p/3698533.html
總結(jié)
以上是生活随笔為你收集整理的[转载]《STL源码剖析》阅读笔记之 迭代器及traits编程技法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: i2c总线协议简介
- 下一篇: 删除隐藏版本信息 版本回退_git之版本