日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

STL源码学习(一)迭代器概念与traits编程技法

發(fā)布時間:2024/4/19 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 STL源码学习(一)迭代器概念与traits编程技法 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

STL的中心思想在于:將數(shù)據(jù)容器和算法分開,彼此獨立設(shè)計,最后再以一貼膠著劑將它們撮合在一起。這種膠著劑便是迭代器,迭代器設(shè)計的目的在于可以方便的獲取(遍歷)容器中的數(shù)據(jù)同時又不暴露容器的內(nèi)部實現(xiàn)。

比如說,當(dāng)使用一個鏈表迭代器時,使用者根本不會知道數(shù)據(jù)在鏈表中是如何存儲的。這帶來的好處是,所有的STL算法只需要接收迭代器最為參數(shù)就夠了,根本不用管是哪個容器的迭代器,只要能夠獲取數(shù)據(jù),通過迭代器改變數(shù)據(jù)就可以了。

不過,迭代器的實現(xiàn)并不是那么簡單,因為在通常使用迭代器時,可能還需要知道迭代器指向的數(shù)據(jù)類型,比如某些算法中需要定義一個同類型的變量。這就產(chǎn)生了矛盾,因為既不想暴露底層數(shù)據(jù),又必須知道數(shù)據(jù)的類型,后面會看到,通過traits技法,可以很容易獲取迭代器所指類型

類型萃取

traits技法

作為容器專屬的迭代器,容器中保存的數(shù)據(jù)類型迭代器是知道的(因為需要作為模板參數(shù)),所以如果在迭代器中定義內(nèi)嵌類型,就可以獲取迭代器所指數(shù)據(jù)的類型,比如定義MyIter迭代器

template <class T> struct MyIter {/* 定義T的別名 */typedef T value_type;T* ptr;MyIter(T* p = 0) : ptr(p) {}T& operator*() const { return *ptr; }//... };templace <class I> /* 使用I的內(nèi)嵌了類型獲取迭代器所指數(shù)據(jù)類型 */ typename I::value_type func(I ite) {return *ite; }//... MyIter<int> ite(new int(8)); cout << func(ite); //輸出8

當(dāng)使用作用域符號表達(dá)一個類型時,需要在前面添加typename顯式指出這是一個型別。因為I是一個模板參數(shù),在具現(xiàn)化之前,編譯器對I一無所知,根本不知道I::value_type是什么,所以需要顯式告訴編譯器,這是一個型別

Traits就是對上述內(nèi)嵌類型獲取迭代器所指數(shù)據(jù)類型方法的封裝,形象地稱為”萃取”迭代器特性,而value_type正是迭代器特性之一

/* 用于萃取迭代器類型,迭代器指向元素的類型等* 使用時可以直接使用* iterator_traits<I>::value_type獲取迭代器指向元素類型 */ template <class Iterator> struct iterator_traits {typedef typename Iterator::value_type value_type; };

通過這個萃取器,如果Iterator聲明有value_type內(nèi)嵌類型,那么就可以使用如下方法獲取迭代器Iterator所指類型

templace <class I> /* 函數(shù)返回型別,通過iterator_traits從I中萃取出它保存的數(shù)據(jù)類型 */ typename iterator_traits<I>::value_type func(I iter) {return *iter; }

指針特化版本

多了一層間接性帶來的好處是可以為iterator_traits定義特化版本,由于原生指針也可以算作迭代器的一種,所以像iterator_traits\

/* 針對原生指針的偏特化版本,因為指針沒有內(nèi)嵌類型 */ template <class T> struct iterator_traits<T*> {typedef T value_type; };/* 針對常量指針的偏特化版本 */ template <class T> struct iterator_traits<const T*> {typedef T value_type; };

有了上面的特化版本,當(dāng)使用iterator_traits\

內(nèi)嵌類型

定義

迭代器部分只有iterator_traits萃取功能不容易理解,剩下的部分是關(guān)于迭代器型別的,包括

  • value type,迭代器指向的數(shù)據(jù)值類型
  • different type,迭代器差類型
  • reference type,迭代器指向的數(shù)據(jù)引用類型
  • pointer type,迭代器指向的數(shù)據(jù)指針類型
  • iterator_category,迭代器類型

這幾種類型在萃取器iterator_traits中也都有相應(yīng)的定義,用于萃取出相應(yīng)型別,同上述的valut_type一樣

/* 用于萃取迭代器類型,迭代器指向元素的類型等 */ /* 使用時可以直接使用* iterator_traits<I>::iteartor_category獲取迭代器I的類型* iterator_traits<I>::value_type獲取迭代器指向元素類型* 依次類推 */ 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; };
  • value type實際上就是迭代器所指對象的型別,也就是模板參數(shù)T。假設(shè)使用MyIter it迭代器,那么value type就是int

  • difference type是指迭代器之間的距離類型,如兩個迭代器作差,保存迭代器之間的距離等,其類型就是difference type,這個類型通常是ptrdiff_t類型

  • reference type是指迭代器所指對象的引用類型,通常是T&

  • pointer type是指迭代器所指對象的指針類型,通常是T*

typedef T value_type;typedef ptrdiff_t difference_type;typedef T& reference;typedef T* pointer;

迭代器類型

在STL中,根據(jù)迭代器所支持的算術(shù)運算,實際上存在多種類型的迭代器,分別是

  • input iterator只讀迭代器,不可以改變迭代器所指對象。只支持++操作
  • ouput iterator只寫迭代器,允許改變迭代器所指對象。只支持++操作
  • forward iterator前向迭代器,可讀寫。只支持++操作
  • bidirectional iterator雙向迭代器,可讀寫。支持++和–操作
  • random access iterator隨機迭代器,可讀寫。支持所有指針?biāo)阈g(shù)操作,包括+,-,+=,-=,++,–等

可以看到,不同類型的迭代器可以提供不同的功能,但這同時也帶來了一些問題,以advance函數(shù)為例,該函數(shù)將給定的迭代器移動n步,然而,不同類型的迭代器支持不同的算術(shù)操作,如果都使用++,那么對隨機迭代器而言就過于耗時(因為本可以直接使用+=)。這就是iterator_category迭代器類型的作用,結(jié)合模板的參數(shù)推導(dǎo)區(qū)分不同的迭代器類型,同時采用最有效的方法進行算術(shù)操作

模板函數(shù)參數(shù)推導(dǎo)功能保證根據(jù)參數(shù)類型選擇最合適的重載函數(shù),所以在STL中,提供了五個類定義分別對應(yīng)五個迭代器類型

/* 定義迭代器類型,每個迭代器中都會將自己迭代器類型typedef成iterator_categories* 由于C++不支持直接獲取類型操作,所以需要利用模板參數(shù)推導(dǎo)實現(xiàn)不同類型的不同操作 */ 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 {};

這五個類定義的繼承關(guān)系和迭代器之間的繼承關(guān)系相同,另外這五個類是空類,因為它的作用僅僅是作為模板參數(shù)用于函數(shù)重載

在迭代器的定義中會根據(jù)自身所支持的功能最強的迭代器類型定義iterator_category,如

typedef random_access_iterator_tag iterator_category;

這樣,當(dāng)再次使用advance函數(shù)時,傳入自己的迭代器類型對應(yīng)的類,同時根據(jù)模板參數(shù)推導(dǎo)就可以調(diào)用不同的函數(shù)

/* 將迭代器i移動n步,n可正可負(fù) */ template <class InputIterator, class Distance> inline void advance(InputIterator& i, Distance n) {/* 不同迭代器支持的操作不同* 只讀,只寫,正向迭代器只支持++操作* 雙向迭代器支持++,--操作* 隨機迭代器支持+=,-=,++,--操作* 為了根據(jù)不同迭代器選擇不同的__advance函數(shù),采用模板參數(shù)推導(dǎo)的方法實現(xiàn)重載 *//* iterator_category()也是一個模板重載,用于創(chuàng)建一個迭代器i的tag對象* 根據(jù)模板參數(shù)推導(dǎo),可以實現(xiàn)__advance重載 */__advance(i, n, iterator_category(i)); }

模板參數(shù)中迭代器類型是InputIterator類型的原因是STL將模板參數(shù)類型設(shè)置為最弱的類型(類似繼承體系中的基類),實際類型會根據(jù)i實際的類型判斷(類似于繼承體系中的多態(tài))

iterator_category函數(shù)用于獲取迭代器對應(yīng)的tag對象

/* 返回迭代器類型對象,注意返回的是一個類對象* 這是因為模板參數(shù)推導(dǎo)只針對類對象進行推導(dǎo)*/ template <class Iterator> inline typename iterator_traits<Iterator>::iterator_category iterator_category(const Iterator&) {typedef typename iterator_traits<Iterator>::iterator_category category;return category(); }

至此,根據(jù)__advance(i, n, iterator_category(i))函數(shù)調(diào)用的第三個參數(shù)類型,模板參數(shù)推導(dǎo)可以實現(xiàn)調(diào)用不同的函數(shù)

/* 針對只讀迭代器的__advance重載 */ template <class InputIterator, class Distance> inline void __advance(InputIterator& i, Distance n, input_iterator_tag) {while (n--) ++i; }/* 針對雙向迭代器的__advance重載 */ template <class BidirectionalIterator, class Distance> inline void __advance(BidirectionalIterator& i, Distance n, bidirectional_iterator_tag) {if (n >= 0)while (n--) ++i;elsewhile (n++) --i; }/* 針對隨機迭代器的__advance重載 */ template <class RandomAccessIterator, class Distance> inline void __advance(RandomAccessIterator& i, Distance n, random_access_iterator_tag) {i += n; }

STL中只提供了三個__advance函數(shù)重載,這是因為上述的繼承體系。由于output迭代器,forward迭代器的__advane操作和input迭代器的操作相同,所以完全可以向上調(diào)用input迭代器的對應(yīng)函數(shù)(好比調(diào)用派生類的某個函數(shù),但是派生類中不存在這個函數(shù),就會向上調(diào)用基類的對應(yīng)函數(shù))

小結(jié)

迭代器部分的難點有兩個,一個是通過traits技法實現(xiàn)類型萃取,另一個是通過模板參數(shù)推導(dǎo)實現(xiàn)函數(shù)重載。不過真正看過源碼后會發(fā)現(xiàn)其實并不困難,當(dāng)然,STL需要內(nèi)部的迭代器都遵循它的規(guī)定,即定義上述的五個型別

總結(jié)

以上是生活随笔為你收集整理的STL源码学习(一)迭代器概念与traits编程技法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。