1. 程式人生 > >《STL原始碼剖析》——迭代器(iterators)概念與traits程式設計技法(一)

《STL原始碼剖析》——迭代器(iterators)概念與traits程式設計技法(一)

一、迭代器設計思維——STL關鍵所在

        STL的中心思想在於:將資料容器(containers)和演算法(algorithms)分開,彼此獨立設計,最後再以一帖粘合劑將它們撮合在一起。

二、迭代器(iterator)是一種 smart pointer

        迭代器是一種行為類似指標的物件,而指標的各種行為中最常見也最重要的便是內容提領(dereference)和成員訪問(member access),因此,迭代器最重要的程式設計工作就是對 operator* 和 operator-> 進行過載(overloading)工作。

        每一種STL容器都提供有專屬迭代器的緣故。

三、Traits程式設計技法——STL原始碼門鑰

        若要 traits 能夠有效運作,每一個迭代器必須遵循約定,自行以內嵌型別定義(nested typedef)的方式定義出相應型別(associated types)。根據經驗,最常用到的迭代器相應型別有五類:value type,difference type,pointer,reference,iterator catagoly。

// "榨汁機"traits
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;
};

        1. 迭代器相應型別之一:value type

        value type,是指迭代器所指物件的型別。任何一個打算與STL演算法有完美搭配的 class,都應該定義自己的value type內嵌型別。

        2. 迭代器相應型別之二:difference type

        difference type 用來表示兩個迭代器之間的距離。針對相應型別 difference type,traits 的如下兩個(針對原生指標而寫的)特化版本,以C++內建的ptrdiff_t(定義於<cstddef>標頭檔案)作為原生指標的difference type:

template<class Iterator>
struct iterator_traits {
    ...
    typedef typename Iterator::difference_type   difference_type;
};

// 針對原生指標而設計的“偏特化(partial  specialization)”版
template <class T>
struct iterator_traits<T *> {
    ...
    typedef ptrdiff_t    difference_type;
};

// 針對原生的 pointer-to-const 而設計的“偏特化(partial specialization)”版
template <class T>
struct iterator_traits<const T*> {
    ...
    typedef ptrdiff_t  difference_type;
};

        3. 迭代器相應型別之三:reference type

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

template<class Iterator>
struct iterator_traits {
    ...
    typedef typename Iterator::pointer pointer;
    typedef typename Iterator::reference  reference;
};

// 針對原生指標而設計的“偏特化(partial  specialization)”版
template <class T>
struct iterator_traits<T *> {
    ...
    typedef T*  pointer;
    typedef T&  reference;
};

// 針對原生的 pointer-to-const 而設計的“偏特化(partial specialization)”版
template <class T>
struct iterator_traits<const T*> {
    ...
    typedef const T*  pointer;
    typedef const T&  reference;
};

        5. 迭代器相應型別之五:iterator_category

        根據移動特性與施行操作,迭代器被分為五類:

                a. Input Iterator:這種迭代器所指的物件,不允許外界改變。只讀(read only)。

                b. Output Iterator:唯寫(write only)。

                c. Forward Iterator:允許“寫入型”演算法在此種迭代器所形成的區間上進行讀寫操作。

                d. Bidirectional Iterator:可雙向移動。某些演算法需要逆向走訪某個迭代器區間,可以使用 Bidirectional Iterator。

                e. Random Access Iterator:前四種迭代器都只供應一部分指標算術能力(前三種支援 operator++,第四種在加上 operator--),第五種則涵蓋所有指標算術能力,包括 p+n, p-n, p[n], p1 - p2, p1 < p2。

四、std::iterator 的保證

        為了符合規範,任何迭代器都應該提供五個內嵌相應型別,以利於 traits 萃取,否則便是自別於整個STL架構,可能無法與其它 STL 元件順利搭配。STL 提供了一個 iterators class 如下,如果每個新設計的迭代器都繼承自它,就可保證符合 STL 所需之規則:

template <class Category,
                  class T,
                  class Distance = ptrdiff_t,
                  class Pointer = T*,
                  class Reference = T&>
struct iterator {
    typedef Category   iterator_category;
    typedef T                value_type;
    typedef Distance    difference_type;
    typedef Pointer       pointer;
    typedef Reference   reference;
};
        由於後三個引數皆有預設值,故新的迭代器只需提供前兩個引數即可。