STL_迭代器

迭代器

Design Pattern中對迭代器的模式定義:提供一種方法能都依序訪問某個聚合物(容器)內所含的各個元素,而又無需暴露該聚合物的內部表述方式。
迭代器是一種相似指針對象,最重要的工做是進行operator*和operator->進行重載,除此以外還有++,==,=這一系列運算符的重載,不可避免地曝光了不少結構的實現細節。因此將迭代器的開發任務交給結構的設計者更加高效。算法

迭代器關聯類型

如何獲取「迭代器所指對象」的類型?解決辦法是使用模板函數參數推導機制。dom

//簡單舉例
template <class I, class T>
void func_impl(I iter,T e) { //T就是迭代器所指之物的類型
    。。。
}

template <class I>
void func(I iter) {//對外接口
    func_impl(iter,*iter);//實際工做
}

Traits

若是value type要用於函數傳回值,使用參數推導就沒有做用了,能夠經過聲明內嵌類型解決。函數

template <class T>
struct Iter {
    typedef T value_type;//內嵌類型
    ...
};

template <calss I>
typename I:value_type func(I iter) { //typename 關鍵字告訴編譯器 value_type表明一個類型
    ...
}//返回類型I:value_type

這種方法僅限於定義了內嵌類型的class type成員,對於原生指針類型,沒法定義內嵌類型。因而引入template partial sepcilization(模板偏特化),即若是class template擁有多個template參數,能夠針對一部分參數進行特化,至關於在泛化設計中提供一個特化版本。設計

template <typename T>
class C<T*> {}; //T*爲原生指針就是T爲任何類型的進一步條件限制。

template <class I>
struct iterator_traits {
    typedef typename I::value_type value_type;
};//若是I定義了 本身的value_type,能夠萃取出value_type;

多了一層間接性能夠擁有特化版本:指針

template <class T>
struct iterator_traits<T*> {
    typedef T value_type;
}//原生指針如int*類型也能夠萃取出value_type;

//可是針對指向常數對象的指針,iterator_traits<const int*>::value_type,獲取類型是const int,可使用另外一種特化
template <class T>
struct iterator_traits<const T*> {
    typedef T value_type;//類型爲T,而非const T
};

根據經驗,最經常使用到的五種關聯類型:value_type,difference type,pointer,reference,iterator category。
value type:迭代器所指對象的類型;code

difference type:兩迭代器之間的距離對象

template <class I,calss T>
typename iterator_traits::difference_type count(I first,I last,const value &value) {
    typename iterator_traits::difference_type n = 0;
    for(;first !=last;++first)
        if(*first == value)
            ++n;
    return n;
}
//針對原生指針,使用內建類型prtdiff_t
template <class T>
struct iterator_traits<T*> {
    typedef prtdiff_t difference_type;
};

reference type:迭代器所指對象內容是否容許改變,分爲constant iterators和mutable iterators,後者應當返回左值,在C++中使用reference方式返回左值。若是mutable iterator p的value type是T,*p類型是T&。blog

pointer type:reference type返回左值表明p所指內容,而pointer type返回左值表明p所指以內容的地址。繼承

iterator_category:首先討論迭代器的分類接口

  • Input Iterator:只讀,只支持operator++
  • Output Iterator:只寫,只支持operator++
  • Forward Iterator:容許「寫入型」算法,執行讀寫操做,只支持operator++
  • Bidirectional Iterator:雙向移動,支持operator++,operator--
  • Random Access Iterator:涵蓋全部指針運算能力

直線與箭頭表明概念與強化關係,若是算法接收一種迭代器,那麼就能夠接受強化類型的迭代器。設計算法時,儘可能針對某種迭代器提供明肯定義,針對強化迭代器提供另外一種定義,才能提供最大效率。任何迭代器屬於其所類型中最強的那個。
a

爲了實現針對不一樣類型迭代器的重載函數,traits應該能萃取出迭代器的類型,以做爲算法的參數之一。

42 struct input_iterator_tag {}; 
 43 struct output_iterator_tag {};
 44 struct forward_iterator_tag : public input_iterator_tag {};
 45 struct bidirectional_iterator_tag : public forward_iterator_tag {};
 46 struct random_access_iterator_tag : public bidirectional_iterator_tag {};
//Input版,模板以算法所能接受的最低階迭代器類型做爲形參
tempalte <class InputIterator,class Distance>
inline void __advance(InputIterator &i,Distance n,input_iterator_tag) {
    while(n--) ++i;
}
// Forward版,傳遞調用Input版
tempalte <class ForwardIterator,class Distance>
inline void __advance(ForwardIterator &i,Distance n,forward_iterator_tag) {
    __advance(i,n,input_iterator_tag());
}
//Bidirectional版支持兩個方向
tempalte <class BidirectionalIterator,class Distance>
inline void __advance(BidirectionalIterator &i,Distance n,bidirectional_iterator_tag) {
    if(n >= 0)
        while(n--) ++i;
    else
        while(n++) --i;
}
//Random Access版
tempalte <class RandomAccessIterator,class Distance>
inline void __advance(RandomAccessIterator &i,Distance n,random_access_iterator_tag) {
    i+=n;
}

最後一個參數用於聲明類型,激活重載,並不使用該參數。

//提供上層接口,最後一個參數產生臨時對象,在編譯時決定調用那個__advance
tempalte <class InputIterator,class Distance>
inline void advance(InputIterator &i,Distance n) {
    __advance(i,n,iterator_traits<InputIterator>::iterator_category());
}

//定義iterator_category()以下:
template <class I>
inline typename iterator_traits<I>::iterator_category iterator_category(const &i) {
    typedef typename iterator_traits<I>::iterator_category category;
    reutrn category();
}

//對於原生指針類型的iterator_category(),是一種RandomAccessIterator
template <class T>
struct iterator_traits<T*> {
    typedef rendom_access_iterator_tag iterator_category;
}

使用struct繼承方式來定義分類標籤,有助於消除「單純傳遞調用函數」。好比前面的advance()的ForwardIterator版,能夠不用寫,編譯器會調用其父類函數(Input版)。(todo:對OutputIterator定位不明朗,forward_tag並無繼承output_tag)
至此,itarator_traits結構包含如下部分:

tempalte <class I>
struct iterator_traits {
    typedef typename I::value_type         value_type;
    typedef typename I::iterator_category  iterator_category;
    typedef typename I::differnce_type     difference_type;
    typedef typename I::pointer            pointer;
    typedef typename I::reference          reference;
};

std::iterator

tempalte <class Catagory,class T,class Distance = ptrdiff_t,class Pointer = T*,class Reference = &T>
struct iterator {
    typedef Category  iterator_category;
    typedef T         value_type;
    typedef Disatnce  difference_type;
    typedef Pointer   pointer;
    typedef Reference reference;
};

//iterator不包含數據,繼承時不會有額外開銷,通常只需提供前兩個參數。
tempalte <class Item>
struct ListIterator:public std::iterator<std::forward_iterator_tag,Item> {
    ...
}

迭代器的做用是設計適當的關聯類型;設計適當的迭代器是容器的責任。而算法則獨立於迭代器和容器。

SGI STL中的__type_traits
SGI將itreator_traits擴展到了__type_traits,如此類型是否具有non-trivial default ctor(constructor),n-t copy ctor,n-t assignment operator 等,若是所具備的都是trivial,對這個類型進行 構造,析構,拷貝時能夠採起最有效的措施,如直接使用內存操做。

__type_traits<T>::has_trivial_default_constructor
__type_traits<T>::has_trivial_copy_constructor
__type_traits<T>::has_trivial_assignment_operator
__type_traits<T>::has_trivial_destructor
__type_traits<T>::is_POD_type

struct __true_type {};
struct __false_type {};
相關文章
相關標籤/搜索