《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;
};
由於後三個引數皆有預設值,故新的迭代器只需提供前兩個引數即可。