STL源碼剖析 迭代器iterator的概念 和 traits編程技法

  • iterator模式定義如下:提供一種方法,使之能夠依序巡訪某個 聚合物(容器)所含的各個元素,而又無需暴露該聚合物的內部表述方式.
  • STL的中心思想在于:將數據容器(containers)和算法(algorithms)分開,彼此獨立設計,最后再以一帖膠著劑將它們撮合在一起。容器和算法的泛型化,從技術角度來看并不困難,C ++的class templates和 function templates可分別達成目標。如何設計出兩者之間的良好膠著劑,才是大難題。

?迭代器 (iterator ) 是一種 smart pointer

  • 迭代器是一種行為類似指針的對象,而指針的各種行為中最常見也最重要的便是內容提領〈dereference)和成員訪問(member access) , 因此,迭代器最重要的 編程工作就是對 operator* 和 operator-> 進行重載(overloading) 工作。關于 這一點,C++標準程序庫有一個auto_ptr可供我們參考任何一本詳盡的C++ 語法書籍都應該談到auto_ptr 這是一個用來包裝原生指 針 (native pointer)的對象,聲名狼藉的內存漏洞(memory leak)問題可藉此獲得解決. auto_ptr用法如下,和原生指針一模一樣:

  • 函數第一行的意思是,以算式new動態配置一個初值為"jjhou” 的 string 對象,并將所得結果(一個原生指針)作為aUtoj>tr<Strin g > 對象的初值。注意, auto_ptr角括號內放的是“原生指針所指對象”的型別,而不是原生指針的型別.?

迭代器相 應 型 別 ( associated types )

  • ?我們以func ()為對外接口,卻把實際操作全部置于func_impl()之中.由于 func_impl ()是一個function template,—旦被調用,編譯器會自動進行template參數推導。于是導出型別T,順利解決了問題。
  • 迭代器相應型別(associatedtypes)不 只 是 “迭代器所指對象的型別”?種而 已。根據經驗,最常用的相應型別有五種,然而并非任何情況下任何一種都可利用上述的template參數推導機制來取得.我們需要更全面的解法。

Traits編程技法— STL源代碼門鑰

  • 迭代器所指對象的型別,稱為該迭代器的value iy p e .上述的參數型別推導 技巧雖然可用于value ty p e ,卻非全面可用:萬一 value typ e 必須用于函數的傳 回值,就束手無策了,畢竟函數的*"template參數推導機制”推而導之的只是參數,無法推導函數的回返值型別。
  • 我們需要其它方法。聲明內嵌型別似乎是個好主意,像這樣:

  • 注 意 ,func ( ) 的回返型別必須加上關鍵詞typename , 因 為 T 是一個 template參數,在它被編譯器具現化之前,編譯器對T 一無所悉,換句話說,編 譯器此時并不知道MyIter<T>: : value_type代表的是一個型別或是一個member function或是一個data m e m b e r . 關 鍵 詞 typename的用意在于告訴編譯器這是一個型別,如此才能順利通過編譯。

  • ?大致的意義是:如 果 class template擁有一個以上的 template參數,我們可以針對其中某個(或數個,但非全部)template參數進行特化工作。換句話說,我們可以在泛化設計中提供一個特化版本(也就是將泛化版本中的某些template參數賦予明確的指定)。

  • ?多了一層間接性,先前使用一個T,現在使用了兩個T
  • 但這除了多一層間接性,又帶來什么好處呢?好處是traits可以擁有特化版本。現在,我們令 iterator_traites 擁有一個 partial specializations 如下

  • ?于是,原生指針i n t * 雖然不是一種class type,亦可通過traits取 其 value type。這就解決了先前的問題。
  • 但是請注意,針 對 “指向常數對象的指針(pointeEo-snst) ”,下面這個 式子得到什么結果
  • iterator_traits<const int*>::value_type
  • 獲得的是const i n t 而非i n t . 這是我們期望的嗎?我們希望利用這種機制來聲 明一個暫時變量,使其型別與迭代器的value type相同,而現在,聲明一個無法 賦 值 (因 c o n s t 之故)的暫時變量,沒什么用!因此,如果迭代器是個pointer-to-const,我們應該設法令其value t y p e 為一個non-const型別。沒問題,只要另外設計一個特化版本,就能解決這個問題:

  • ?現在,不論面對的是迭代器My I t e r , 或是原生指針i n t * 或 const int*,都可以通過traits取出正確的(我們所期望的)value type。?
  • 特性萃取機”角色,萃取各個迭代器的特性。 這里所謂的迭代器特性,指的是迭代器的相應型別(associated types)。當然,若 要 這 個 “特性萃取機” traits能夠有效運作,每一個迭代器必須遵循約定,自行以內嵌型別定義(nested typedef)的方式定義出相應型別(associated types) 。這是一個約定,誰不遵守這個約定,誰就不能兼容于S T L 這個大家庭。

  • ?根據經驗,最常用到的迭代器相應型別有五種:value 1ype, difference iype, pointer, reference, iterator catagoly。如果你希望你所開發的容器能與STL水乳交融,一定要為你的容器的迭代器定義這五種相應型別。 “特性萃取機” traits會很 ?實地將原汁原味榨取出來:

?3.4.2 迭 代 器 相應型別之二:difference type

  • difference type用來表示兩個迭代器之間的距離,因此它也可以用來表示一個 容器的最大容量,因為對于連續空間的容器而言,頭尾之間的距離就是其最大容量.
  • 如果一個泛型算法提供計數功能,例如STL的 count(), 其傳回值就必須使用迭代器的 difference type:

  • ?針對相應型別difference type, traits的如下兩個(針對原生指針而寫的)特 化版本,以 C++內建的ptrdiff_t (定義于<cstddef>頭文件)作為原生指針的 difference type:
  • ptrdiff_t是C/C++標準庫中定義的一個與機器相關的數據類型。ptrdiff_t類型變量通常用來保存兩個指針減法操作的結果

?3.4.3 迭代器相應型別之三:reference type

  • 從 “迭代器所指之物的內容是否允許改變”的角度觀之,迭代器分為兩種:不 允 許 改 變 “所指對象之內容”者,稱為constant iterators,例 如 const int*pic; 允許改變"所指對象之內容”者,稱 為 mutable iterators, 例 如 int* pio當我們對 一 個 mutable iterators進行提領操作時,獲得的不應該是一個右值(rvalue), 應該是一個左值(lvalue), 因為右值不允許賦值操作(assignm ent), 左值才允許:

  • ?在 C ++中,函數如果要傳回左值,都是以by reference的方式進行,所以當p 是 個 mutable iterators時,如果其value type 是 T,那 么 * p 的型別不應該是T, 應該是T&
  • 將此道理擴充,如果p 是 一 個 constant iterators,其 value type 是 t ,那 么 * p 的型別不應該是const T , 而應該是const T&。這里所討論的* p 的型 別,即所謂的reference type

迭代器相應型別之四:pointer type

  • pointers和 references在 C + + 中有非常密切的關聯。如 果 “傳回一個左值, 令它代表P 所指之物”是可能的,那 么 “傳回一個左值,令它代表P 所指之物的地址”也一定可以。也就是說,我們能夠傳回一個pointer,指向迭代器所指之物。

  • item& 便是 Listlier 的 reference type ,而 item * 便是其 pointer type

?迭代器 相 應 型 別 之 五 :iterator_category

  • 最后一個(第五個)迭代器的相應型別會引發較大規模的寫代碼工程。在那之前,我必須先討論迭代器的分類
  • 根據移動特性與施行操作,迭代器被分為五類:

  • ?盡量針對圖3? 2中的某種迭代器提供一個明確定義,并針對更強化的某種迭代器提供另一種定義,這樣才能在不同情況下提供最大效率。在研究STL的過程中,每一分每一秒我們都要謹記在心,效率是個重要課題。假設有個算法可接受Forward Iterator,你 以 Random Access Iterator喂給它, 它當然也會接受,因為一個Random Access Iterator必然是一個Forward Iterator(見圖3-2) 。但是可用并不代表最佳!

以 advanced。 為例

  • 拿 advance () 來 說 (這是許多算法內部常用的一個函數),該函數有兩個 參數,迭代器P 和數值n;函數內部將p 累進n 次 (前進n 距離)。下面有三份定義,一份針對 Input Iterator, 一份針對 Bidirectional Iterator,另一份針對 Random Access Iteratoro倒是沒有針對Foiv/ardlterator而設計的版本,因為那和 針 對 Inputiterator而設計的版本完全~致。
  • 設計考慮如下:如 果 traits有能力萃取出迭代器的種類,我們便可利用這個 “迭代器類型”相應型別作為advanced 0 的第三參數。這個相應型別一定必須是一個class type,不能只是數值號碼類的東西,因為編譯器需仰賴它(一個型別)來進行重載決議(overloaded resolution) o 下面定義五個classes,代表五種迭代器類型:

  • ?這 些 classes只作為標記用,所以不需要任何成員。至于為什么運用繼承機制, 稍后再解釋。現在重新設計— advance。 (由于只在內部使用,所以函數名稱加 上特定的前導符),并加上第三參數,使它們形成重載:

?

  • ?注意上述語法,每個— advanced 的最后一個參數都只聲明型別,并未指定 參數名稱,因為它純粹只是用來激活重載機制,函數之中根本不使用該參數。如果硬要加上參數名稱也可以,畫蛇添足罷了。
  • 行進至此,還需要一個對外開放的上層控制接口,調用上述各個重載的_advance()。這一上層接口只需兩個參數,當它準備將工作轉給上述的 _advance ()時,才自行加上第三參數:迭代器類型。因此,這個上層函數必須有 能力從它所獲得的迭代器中推導出其類型—— 這份工作自然是交給traits機制:

  • ?任何一個迭代器,其類型永遠應該落在“該迭代器所隸屬之各種類型中,最強化的那個”。例如,int* 既是 Random Access Iterator,又是 Bidirectional Iterator, 同時也是Forward Iterator,而且也是Input Iterator,那么,其類型應該歸屬為 random_access_iterator_tag?
  • 按 說 advanced()既然可以接受各種類型的迭代器,就不應將其型別參數命 名為Inputiterator。這其實是STL算法的一個命名規則:以算法所能接受之最 低階迭代器類型,來為其迭代器型別參數命名
  • 消 除 "單純傳遞調用的函數
  • 以 class來定義迭代器的各種分類標簽,不僅可以促成重載機制的成功運作 (使編譯器得以正確執行重載決議,overloaded resolution), 另一個好處是,通過繼承,我們 可 以 不 必 再 寫 “單純只做傳遞調用”的函數(例如前述的 advance() Forwarditerator版 ) 。為什么能夠如此?考慮下面這個小例子,從其輸出結果可以 看出端倪:

?以 d is ta n c e ()為 例

  • 關 于 “迭代器類型標簽”的應用,以下再舉一例。distance ()也是常用的一個迭代器操作函數,用來計算兩個迭代器之間的距離。針對不同的迭代器類型,它可以有不同的計算方式,帶來不同的效率。整個設計模式和前述的advance ()如出一轍:

  • ?distance使用 category動態適配 InputIterator和randomAccessiterator,分別調用與之匹配的__distance函數,但是這個 distance使用的時候 <> 需要指定最小的迭代器類型,來為迭代器進行命名

  • ?注意,distanced可接受任何類型的迭代器;其 template型別參數之所以命 名 為 Inputiterator,是為了遵循STL算法的命名規則:以算法所能接受之最初 級類型來為其迭代器型別參數命名.此外也請注意,由于迭代器類型之間存在著繼承關系, “傳遞調用(forwarding) ”的行為模式因此自然存在一 一點我已在 前一節討論過。換句話說,當客端調用distanced并使用Output Iterators或Forward Iterators 或 BidirectionaI Iterators 時,統統都會傳遞調用 Input Iterator 版
    的那個_ distance ( ) 函數。

std::iterator 的保證

  • 了符合規范,任何迭代器都應該提供五個內嵌相應型別,以利于traits萃取,否則便是自別于整個STL架構,可能無法與其它STL組件順利搭配。然而寫代碼難免掛一漏萬,誰也不能保證不會有粗心大意的時候。如果能夠將事情簡化,就好多了。STL提供了一個iterators class如下,如果每個新設計的迭代器都 繼承自它,就可保證符合STL所需之規范:

  • ?設計適當的相應型別(associated types) , 是迭代器的責任。設計適當的迭代 器,則是容器的責任.唯容器本身,才知道該設計出怎樣的迭代器來遍歷自己,并執行迭代器該有的各種行為(前進、后退、取值、取用成員…) 。至于算法,完全可以獨立于容器和迭代器之外自行發展,只要設計時以迭代器為對外接口就行。

ite ra to r源代碼完整重列

  • SGI STL<stl_iterator.h>頭文件內與本章相關的程序代碼。該頭文件還有其它內容,是關于 iostream iterators, inserter iterators 以及 reverse iterators 的實現,將于第8 章討論。

?我并不是很懂為啥要再包裝一層

?SGI STL 的 私 房 菜 :__type_traits

  • traits編程技法很棒,適度彌補了 C++語言本身的不足。STL只對迭代器加 以規范,制定出itera to r_ tra its這樣的東西。SG I把這種技法進一步擴大到迭 代器以外的世界,于是有了所謂的_ type_tra-itso 雙底線前綴詞意指這是SGI STL內部所用的東西,不在STL標準規范之內?
  • iterator_ traits負責萃取迭代器的特性,—type_ traits則負責萃取型別(type)的特性
  • 此處我們所關注的型別特性是指:這個型別是否具備non-trivial defaltctor ? 是否具備 non-trivial copy ctor ? 是否具備 non-trivial assignment operator?是否具備non-trivial dtor?如果答案是否定的,我們在對這個型別進行構造、析構、拷貝、賦值等操作時,就可以采用最有效率的措施(例如根本不調用身居高位,不謀實事的那些constructor, destructor), 而采用內存直接處理操作如 malloc. memcpy等等,獲得最高效率。這對于大規模而操作頻繁的容器, 有著顯著的效率提升4。

  • ?我們希望上述式子響應我們“真”或 “假”(以便我們決定采取什么策略),但其結果不應該只是個bool值,應該是個有著真/假性質的“對象”,因為我們 希望利用其響應結果來進行參數推導,而編譯器只有面對Class object形式的參數, 才會做參數推導。為此,上述式子應該傳回這樣的東西:

  • ?為了達成上述五個式子,— type_traits內必須定義一些typedefs,其值不是 _ true_type 就是 _ false_type下面是 SGI 的做法:

POD

?

例子

?

?

?

?

?

?

?

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/446416.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/446416.shtml
英文地址,請注明出處:http://en.pswp.cn/news/446416.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

中科大 計算機網絡11 應用層原理

應用層大綱 傳輸層向應用層提供的服務&#xff0c;形式是Socket API&#xff08;原語&#xff09; 一些網絡應用的例子 互聯網層次中&#xff0c;應用層協議最多 流媒體應用&#xff1a;直播 網絡核心最高的層次就是網絡層 應用進程通信方式 C/S&#xff1a; 客戶端&…

STL源碼剖析 序列式容器 vector 和 ilist

Vector list 單向鏈表 ilistlist的刪除操作&#xff0c;也只有指向被刪除元素的迭代器會失效&#xff0c;其他迭代器不會受到影響

中科大 計算機網絡5 接入網和物理媒體

接入網 接入網&#xff1a;把邊緣&#xff08;主機&#xff09;接入核心&#xff08;路由器&#xff0c;交換機&#xff09; 骨干網【連接主機和主機】和接入網中都有物理媒體 接入方式&#xff1a;有線和無線 帶寬共享/獨享 接入網&#xff1a;住宅接入modem modem調制解調…

STL源碼剖析 序列式容器 deque雙端隊列

相較于vector的內存拷貝&#xff0c;deque在內存不足時只需要進行內存的拼接操作即可&#xff0c;不需要重新配置、復制、釋放等操作&#xff0c;代價就是迭代器的架構不是一個普通的指針&#xff0c;比較復雜d e q u e 的迭代器 deque是分段連續空間。維持其“整體連續”假象…

中科大 計算機網絡6 Internet結構和ISP

互聯網的結構 端系統通過接入ISPs接入互聯網 n個ISP互相連接&#xff1a; IXP,Internet exchage point:互聯網接入點&#xff0c;互聯網交互點 ISP&#xff1a;互聯網服務提供商&#xff0c;提供接入&#xff0c;提供網絡【中國移動&#xff0c;中國電信】 ICP&#xff1a…

STL源碼剖析 Stack棧 queue隊列

隨機迭代器用于隨機數據訪問&#xff0c;所以棧stack不具備此功能

中科大 計算機網絡8 協議層次和服務模型

協議層次 協議層次&#xff1a;現實生活中的例子 分層 分層處理和實現復雜系統 圖中&#xff0c;左邊是模塊&#xff0c;右邊是分層 計算機的設計是分層&#xff0c;每一層實現一個或一組功能&#xff0c;下層向上層提供服務&#xff1b;但效率比較低 對等層實體通過協議來交換…

STL源碼剖析 heap堆結構

heap一般特指max-heap&#xff0c;即最大的元素位于heap和array的首部 heap不提供遍歷功能&#xff0c;也不提供迭代功能

中科大 計算機網絡9 互聯網歷史

總綱 計算機網絡 早期1960以前 1961-1972 NCP協議&#xff1a;相當于現在的TCP和IP協議 每個節點即是數據的源也是數據的目標

STL源碼剖析 序列式容器 slist

STL l i s t 是個雙向鏈表(double linked lis t) 。SGI STL提供了一個單向鏈 表 (single linked lis t) , 名 為 slist s l i s t 和 l i s t 的主要差別在于&#xff0c;前者的迭代器屬于單向的Forwardlterotor, 后者的迭代器屬于雙向的Bidirectional Iterator.為此&#xff0…

中科大 計算機網絡12 Web和HTTP

Web與HTTP 對象&#xff1a;web頁中其實是對象鏈接 URL&#xff1a;通用資源定位符【任何對象都可以使用URL來唯一標識】 用戶名&#xff1a;口令【支持匿名訪問&#xff0c;用戶名和口令不計】 端口&#xff1a;HTTP&#xff1a;80 FTP&#xff1a;21【使用默認端口號&#x…

STL源碼剖析 關聯式容器 樹 紅黑樹、二叉搜索樹、平衡二叉搜索樹

所謂關聯式容器&#xff0c;觀念上類似關聯式數據庫(實際上則簡單許多)&#xff1a;每筆數據(每個元素)都有一個鍵值(key)和一個實值(value) 2。當元素被插入到關聯式 容器中時&#xff0c;容器內部結構(可能是RB-tree,也可能是hash-table)便依照其鍵 值大小&#xff0c;以某種…

北京大學 軟件工程1 軟件 軟件工程 軟件開發 軟件工程框架

軟件的定義 重新定義軟件 新一代信息技術 區塊鏈 創造性思維 軟件的特點 軟件的種類 支撐軟件&#xff1a;VC&#xff0c;PyCharm等 應用軟件&#xff1a;QQ&#xff0c;微信 軟件工程的起源 軟件開發的三個階段 軟件工程概念的提出 軟件工程的定義 軟件工程將系統化&#…

java學習_Python基礎學習教程:從0學爬蟲?讓爬蟲滿足你的好奇心

Python基礎學習教程&#xff1a;從0學爬蟲&#xff1f;讓爬蟲滿足你的好奇心有必要學爬蟲嗎&#xff1f;我想&#xff0c;這已經是一個不需要討論的問題了。爬蟲&#xff0c;“有用”也“有趣”&#xff01;這個數據為王的時代&#xff0c;我們要從這個龐大的互聯網中來獲取到我…

安卓rom制作教程_安卓手機TWRP_Recovery卡刷圖文教程 適用于卡刷ROM,TWRP救磚

掃一掃二維碼&#xff0c;關注我&#xff0c;解決刷機各種疑難雜癥 ROM樂園獨家支持最近有很多小伙伴問怎么去卡刷&#xff0c;卡刷的操作是什么&#xff0c;什么是卡刷&#xff0c;小編就仔細來寫一下卡刷教程吧&#xff0c;記住&#xff0c;我們所說的卡刷&#xff0c;并不是…

東軟 軟件工程1 軟件危機 軟件工程 軟件生命周期

軟件危機 軟件危機產生的原因 消除軟件危機的途徑&#xff1a; 軟件工程歷史 軟件工程的概念 軟件工程項目的基本目標 軟件工程的基本原理 軟件生命周期 軟件工程的中的軟件生命周期

iphone全部機型_iPhone 12 銷量或創 iPhone 6 以來最高|iphone|郭明錤

iPhone 12 系列目前正在預售中&#xff0c;本周五兩款 英寸機型就將正式上市。有不少小伙伴已經成功預購到了首批 iPhone 12&#xff0c;另有一些用戶仍在持幣觀望&#xff0c;等待第三方平臺報出更便宜的價格。而從 iPhone 12 的預售情況來看&#xff0c;兩款 英寸機型還是相當…

東軟 軟件工程2 軟件開發模型 瀑布模型 原型模型 螺旋模型 統一過程模型RUP 敏捷開發模型

軟件開發過程模型 瀑布模型 原型模型 螺旋模型 統一過程模型-RUP 敏捷開發模型 敏捷開發模型&#xff1a;Scrum方法 敏捷開發模型&#xff1a;進行Scrum開發