迭代器iterator和traits程式設計技法

2022-03-20 04:57:53 字數 3485 閱讀 4757

迭代器定義:提供一種方法,使之能夠依序巡訪某個聚合物(容器)所含的各個元素,而無需暴露該聚合物的內部表述方式。

stl的中心思想在於:將資料容器和演算法分開,彼此獨立設計,然後再以一貼膠著劑撮合在一起。在stl中,迭代器就扮演著膠著劑的作用。迭代器是一種類似指標的物件,而指標的各種行為中最常見也是最重要的便是解引用和成員訪問,因此迭代器最要的程式設計工作就是對operator*和operator->進行過載。

認識迭代器之前我覺得有必要了解一下c++中兩個非常重要的程式設計正規化,即gp(泛型程式設計)oop(物件導向程式設計)。

泛型程式設計:亦稱為"靜態多型",多種資料型別在同一種演算法或者結構上皆可操作,其效率與針對某特定資料型別而設計的演算法或結構相同, 具體資料型別在編譯期確定,編譯器承擔更多,**執行效率高。在stl中利用gp將methods和datas實現了分而治之。

物件導向程式設計:將methods和datas關聯到一起 ,也就是方法和成員變數放到乙個類中實現,通過繼承的方式,利用虛函式表(virtual)實現執行時型別判定,也叫"動態多型", 由於執行過程中需根據型別去檢索虛函式表,因此效率相對較低。

stl全部採用泛型程式設計,因此,相對來說stl的效率較高且易於維護。

在stl演算法中需要用到迭代器相應型別,即迭代器所指物件的型別。但c++只支援 sizeof() 並未支援 typeof() 。stl的解決方法之一是利用 function template 的引數推導機制,但 value type 必須用於函式的返回值時 function template 就束手無策。stl利用class類的宣告內嵌型別以及針對原生指標的偏特化方式,設計迭代器的萃取機萃取迭代器的特性,解決用於函式返回值的問題,value type 是迭代器的特性之一。下面是stl原始碼利用class類的宣告內嵌型別設計的萃取機,也是萃取機的泛化版本:

//

stl萃取器的泛化版本

template

struct

iterator_traits ;

因為原生指標不是class type,無法為它定義內嵌型別。stl利用c++偏特化的方式為泛化設計提供乙個特化版本,即將泛化版本中的某些template引數賦予明確的指定。下面是stl原始碼針對原生指標t*設計的特化版本萃取機,原始碼還設計了乙個const t*原生指標的特化版本,與t*型別這裡不再呈現原始碼:

//

針對t*型別的原生指標設計的特化版本

template

struct iterator_traits;

然後stl原始碼設計了乙個獲取迭代器 value type 的全域性函式,將迭代器作為引數,函式可返回迭代器的型別,具體源**如下:

templateinline typename iterator_traits

::value_type*value_type(

const iterator&)

原始碼還設計了獲取迭代器其他特性 iterator_categoty 和 distance_type 的全域性函式,和value_type類似,原始碼如下:

templateinline typename iterator_traits

::iterator_category

iterator_category(

const iterator&)

template

inline typename iterator_traits

::difference_type*distance_type(

const iterator&)

這種萃取程式設計技法是stl迭代器實現最重要的方法,萃取機能夠萃取各種迭代器的特性。正是這種技法彌補了c++沒有typeof()功能的缺陷,讓迭代器能夠真正脫離於容器,應用於演算法中去。

stl原始碼中定義五個classes代表五種迭代器的型別,定義如下:

//

五種迭代器型別

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 {};

這些classes只作為標記用,所以不需要任何成員。這五種迭代器型別的關係如下圖所示:

上圖能夠非常明確看出迭代器的分類和從屬關係,設計演算法時,如有可能,我們盡量針對上圖的某種迭代器提供乙個明確定義,並針對更強化的某種迭代器提供另一種定義,保證在不同情況下提供最大效率。在原始碼中 advance 演算法的實現非常能體現這一設計原則。函式入口和針對不同迭代器不同的定義的原始碼如下:

//

advance函式入口

templateinline

void advance(inputiterator&i, distance n)

//inputiterator型別定義

templateinline

void __advance(inputiterator&i, distance n, input_iterator_tag)

//bidirectionaliterator型別定義

templateinline

void __advance(bidirectionaliterator&i, distance n,

bidirectional_iterator_tag)

//randomaccessiterator型別定義

templateinline

void __advance(randomaccessiterator&i, distance n,

random_access_iterator_tag)

上面的原始碼分別對 inputiterator、bidirectionaliterator 和 randomaccessiterator 三種型別的迭代器設計了不同的 __advance 定義,根據第三引數的不同,使函式形成過載。第三引數只是宣告型別並未指定引數名稱,因為它純粹只是用來啟用過載機制,函式根本不使用該引數。從原始碼可以看出 advance 函式根據 iterator_category 獲取迭代器型別而過載不同的 __advance 函式,而函式的過載過程是發生在編譯期,所以函式的執行效率非常高。

行文至此,我認為已經將stl原始碼中迭代器和和萃取程式設計技巧的核心思想總結出來,具體的原始碼實現可以參考我github的實現:關於迭代器的原始碼在 stl_iterator.h 檔案中。

容器vector和迭代器iterator 使用

容器vector宣告方式 vector 型別 變數名 引數 使用前需要引用 incude 初始化方式有下面幾種 1 宣告初始化例如 vectorvct 預設建構函式為空 vectorvct1 vct 用已宣告好容器來初始化 vectorvct2 3,5 大小為3的容器初始化三個都等於5 vector...

c 迭代器iterator 和 vector

初始化vector vectorv1 vectorv2 v1 vectorv3 n,i v3包含了n個值為i的元素 vectorv4 n v4含有初始化元素的n個副本 empty 判斷向量是否為空 begin 返回向量迭代器的首元素 end 返回向量迭代器末元素的下乙個元素 front 返回第乙個資...

C 迭代器iterator和指標

1.指標和iterator都支援與整數進行 運算,而且其含義都是從當前位置向前或者向後移動n個位置 2.指標和iterator都支援減法運算,指標 指標得到的是兩個指標之間的距離,迭代器 迭代器得到的是兩個迭代器之間的距離 3.通過指標或者iterator都能夠修改其指向的元素 指標是c語言裡面就有...