重讀STL原始碼剖析 迭代器

2022-09-03 01:18:12 字數 2729 閱讀 1772

首先關於迭代器:

迭代器不屬於容器,它與容器屬於不同的類,但通過迭代器(迭代器中有某些成員變數;同時也對*等運算子進行了過載),可以訪問到容器內的元素(比如list的迭代器,它不屬於list,但它裡面存放了乙個指標,這個指標指向list結構裡的成員node,這樣就可以借用迭代器去訪問容器了。迭代器並不屬於容器,它只是個工具)。迭代器可以繼承自乙個公用的迭代器(當然也有沒有繼承的,如deque)。

迭代器的目的是用於黏合容器和演算法,演算法以迭代器為媒介,通過迭代器去對容器中的資料進行計算。

相應型別:

在演算法中,對容器內的元素進行操作時,有時候需要使用到容器內的變數的型別,如要宣告乙個和迭代器所指向的元素相同類別的變數,這個時候處理就很困難了。

解決辦法是利用函式末班的引數推導:

templateinline void func(i iter)

template void func_impl(i iter, t t)

這裡為什麼要將func作為介面,而將實際操作交給func_impl呢?

這是因為我們在呼叫時,只希望傳遞迭代器就好了,即以這樣的方式呼叫: func(&i);(&i相當於迭代器,i相當於這個迭代器所指向的元素)

而如果不加一層封裝只能這樣使用:

templatevoid func(i iter,t t)

這樣的使用的問題在於,每次使用func都要將迭代器所指向的元素暴露出來:

func(&i,i);

而在這種情況下func(&i)這樣呼叫是非法的。

因此加一層封裝可以使呼叫更符合這種設計模式,即將一切都隱藏在迭代器以下。

實際上,首先func(&i)首先在func中推導出i為int*型,然後轉入func_impl,在func_impl呼叫時,經由(&int,int)中第二個引數推導出迭代器指向的元素的型別為int,推導出t為int,然後用int建立tmp.

在上面的討論中,實現了在演算法內部宣告迭代器所指向元素類別的功能,但是當演算法的返回值也要是迭代器所指向的元素的類別時呢?

在這種情況下,是無法以上面的方式實現這個功能的。

因此大佬們換了個思路,在設計迭代器的時候,在迭代器的模板內部宣告了迭代器所指向的元素的型別t為value_type.

即:

templatestruct iterator

這樣,我們可以通過iterator::value_type的形式來宣告乙個變數,這個變數就是迭代器所指向的元素的型別。

templatetypename i::value_type

func(i ite)

這樣,如果我們呼叫函式func:向里傳入乙個迭代器,函式模板將i判定為迭代器的型別,然後據此將返回值的型別判斷為迭代器所指向的值得型別,因為我們在迭代器內部已經宣告了value_type為一種型別了。同時,我們也可以用這種方式在迭代器的內部宣告乙個迭代器所指向的元素的變數。

看上去非常巧妙,但這個方法有乙個問題:

問題在於,如果我們要通過這種方式來推導返回值的型別和在演算法內部宣告乙個迭代器所指向的元素的型別的變數,必須要求在迭代器內部宣告它所指向的元素的型別為value_type。但在基本資料型別情況下這是做不到的,因為像int*,char*這些型別,他們是基本的資料型別,我們無法在裡面人為的新增typedef int value_type這種宣告語句。

但像如果將int*這種原生指標都排除在外,拿迭代器的設計還有意義嗎?

在上述問題下,大佬們通過模板偏特化來解決這個問題。

模板偏特化相當於提供乙個更為具體的模板,在進行推導時,實際上會選取更為貼近所推導型別的模板來進行使用,因此完全可以為這些原始指標設計偏特化版本來解決。

偏特化的意思是提供另乙份模板定義是,其本身還是模板,但模板引數更進一步加上了條件限制。

比如:

template class a 

;template class a;

其中,當用aa;時,int*將會使用第二個模板,因為相比第乙個,t*相比t更貼近於指標的形式。

另外注意,第二個是無法單獨存在的,也就是說如果刪除第乙個模板將會報錯,偏特化是依賴於最普遍的那個模板而存在的。

現在,就可以引入這部分的核心了,trait程式設計技法:

首先看下這個模板類:

templatestruct iterator_traits

這個模板是最普通話的模板,也就是說所有的偏特化的模板都基於這個版本之上。

現在再來看前面寫的func函式:

template typename iterator_traits::value_type

func(i ite)

{};

現在,只要我們呼叫func函式,並將迭代器傳入,將自動推導出i的型別,並將返回值的型別設定為迭代器類裡面的value_type型別。

此外,我們可以使用這個模板設計出若干個偏特化版本,如t*,const t*,這樣,所有的型別都統一到了迭代器下,我們可以使用迭代器指向任何元素,演算法也可以推導出相應的型別。

迭代器所指向的元素的類別vlaue_type只是相應型別中的一種,還有很多種,下面展開介紹。

重讀STL原始碼剖析 hashtable

hashtable的設計是乙個vector陣列,每個陣列內為乙個鍊錶,煉錶鏈著hash到同位置的節點,但鍊錶的實現不是list或slist hashtable的節點設計 1.儲存元素值的變數val 2.乙個指向下乙個節點 同乙個bucket內的 的指標next hashtable的迭代器 1.內部維...

STL原始碼剖析 迭代器

一 迭代器 迭代器五種相應型別 1.valuetype,是指迭代器所指物件的型別。2.differencetype,用來表示迭代器之間的距離,可以用來表示乙個容器的最大容量。例如stl中的count 函式,其返回值就是difference type。3.referencetype,在c 中如果要傳回...

STL原始碼剖析 迭代器

迭代器是一種模式,實現了通過乙個統一介面訪問stl容器的方法。stl作為橋梁鏈結了stl演算法與容器。例如,我們可以通過sort a.begin a.end 完成一次利用演算法對vector型別容器a的排序。標準stl中,迭代器在容器內部,每種容器都有自己專屬的迭代器。這樣做的原因是,如果要建立迭代...