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