STL 源碼剖析:配接器 (stack,queue,插入迭代器,反向迭代器,流迭代器)

​ STL 所提供的各種配接器中,改變仿函數 (functors) 接口者,我們稱爲 function adapter,改變容器 (containers) 接口者,我們稱爲 container adapter,改變迭代器 (iterators) 接口者,我們稱爲 iterator adapter。

//
//

應用於容器:STL 所提供的兩個容器,queue 和 stack,其實都是一種配接器。它們的內部都有一個 deque 容器。所有的操作都是通過這個 deque 容器來實現的,即轉調用這個容器的操作。同時,根據 stack 或者 deque 自己的需求定義出需要的接口即可。

//
//

應用於迭代器:包括 insert iterators,reverse iterators,iostream iterators。

//
//

應用於仿函數:functor adapters 是所有配接器中數量最龐大的一個族羣,其配接靈活度也是前兩者所不能及,可以配接、配接、再配接。這些配接操作主要包括 繫結(bind),否定(negate),組合(compose),以及對一般函數或成員函數的修飾 (使其成爲一個仿函數)。

//
//

插入迭代器,insert iterators

back_insert_iterators 源碼

template <class Container>
class back_insert_iterator {
protected:
    Container* container;	// 底層容器

public:
    typedef output_iterator_tag iterator_category;		// 注意類型
    typedef void value_type;
    typedef void difference_type;
    typedef void pointer;
    typedef void reference;

    // 下面這個 constructor 使 back_insert_iterator 與容器綁定起來
    explicit back_insert_iterator(Container &x) : container(&x) { }
    back_insert_iterator<Container>&
    operator= (const typename Container::value_type &value) {
        container -> push_back(value);		// 這裏是關鍵,轉而調用 push_back()
        return *this;
    }

    // 以下三個操作符對 back_insert_iterator 不起作用
    // 都是返回 back_insert_iterator 自己
    back_insert_iterator<Container>& operator*() { return *this; }
    back_insert_iterator<Container>& operator++() { return *this; }
    back_insert_iterator<Container>&  operator++(int) { return *this; }
};

// !! 通常,我們都調用這個輔助函數來使用 back_insert_iterator
template <class Container>
inline back_insert_iterator<Container> back_inserter(Container &x) {
    return back_insert_iterator<Container>(x);
}

對於 front_insert_iterator 實現源碼,幾乎和上面一樣。除了在第 17 行採用的是 push_front 之外沒有差別。

//
//

而對於 insert_iterator 實現源碼,根據 insert() 函數,我們知道,不僅需要知道容器是哪個,而且還要指明插入的位置。所以 insert_iterator 源碼是這樣的:

template <class Container>
class insert_iterator {
protected:
    Container* container;	// 底層容器
    typename Container::iterator iter;

public:
    // 與上面一樣的 5 個 typedef

    // 下面這個 constructor 使 insert_iterator 與容器綁定起來
    insert_iterator(Container &x, typename Container::iterator i) : container(&x), iter(i) { }
    insert_iterator<Container>&
    operator= (const typename Container::value_type &value) {
        iter = container -> insert(iter, value);
        ++ iter;		// !!這裏需要注意,使 insert iterator 永遠隨着其目標貼身移動
        return *this;
    }

    // 與上面相同的不起作用的 operator*(), operator++(), operator++(int)
};

// !! 通常,我們都調用這個輔助函數來使用 insert_iterator
template <class Container, class Iterator>
inline back_insert_iterator<Container> inserter(Container &x, Iterator i) {
    typedef typename Container::iterator iter;
    return insert_iterator<Container>(x, iter(i));
}

反向迭代器 reverse iterators

反向迭代器 reverse iterators,就是將迭代器的行爲倒轉。它的所有操作都和正向迭代器相反。例如,對反向迭代器,++ iter 其實就是正向迭代器的 – iter。

//
//

同時,調用這個迭代器,會從尾到頭處理序列。例如:find(v.rbegin(), v.rend(), value),就會從尾到頭進行對 value 的查找操作。

//
//

而且還需要知道一點,反向迭代器的位置其實是其正向迭代器的對應位置 - 1,這一點很重要。原正向迭代器表示的範圍爲 [begin(), end());到反向迭代器,就應該是(rbegin(), rend()],所以會有上面的關係。

//
//

有了上面那一點,其實 reverse iterators 的實現就並不複雜了。在類中記錄對應的正向迭代器的位置 cur 即可,解引用即解引用 cur - 1 的位置;其他操作通通反着寫(operator++,其實是 – cur 這樣。)

​ 這裏就不貼上代碼了。

//
//

iostream iterators

分爲 istream _iterator 有 ostream_iterator,會分別綁定到一個輸入流,輸出流。與插入迭代器很類型,對其的賦值操作就分別相當於在綁定的輸入流上進行輸入,或者在綁定的輸出流上進行輸出。

//
//

所以我們可以想象大體實現,除了與之前類似的 5 個 typedef 之外,我們需要在類內部指定一個 istream 流或者 ostream 流,在構造函數中進行綁定。然後重載 operator*() 等運算符即可。

//
//

istream_iterator 中,迭代器每前進一次就代表進行一次輸入。而 ostream_iterator 中,每進行一次賦值就代表要輸出一次。

//
//

不過需要注意:istream_iterator 的讀入需要每一次都確定流的狀態。(是否遇到了 eof 或者 讀入的類型與要求的類型不符)。對於 ostream_iterator 中直接進行輸出即可。

​ 貼上一份具體的 istream_iterator 代碼:

template <class T, class Distance = ptrdiff_t>
class istream_iterator {
    friend bool
    operator== __STL_NULL_TMPL_ARGS(const istream_iterator<T, Distance>& x,
                                   const istream_iterator<T, Distance>& y);
    
protected:
    istream *stream;
    T value;
    bool end_marker;
    void read() {
        end_marker = (*stream) ? true : false;
        if(end_marker) *stream >> value;		// 關鍵
        // 以上,輸入之後,stream 的狀態可能改變,所以下面再判斷一次以決定 end_marker
        end_marker = (*stream) ? true : false;
    }
    
public:
    typedef input_iterator_tag iterator_category;
    typedef T value_type;
    typedef Distance difference_type;
    typedef const T* pointer;			// 流不可複製
    typedef const T& reference;
    
    istream_iterator() : stream(&cin), end_marker(false) {}
    istream_iterator(istream &s): stream(&s) { read(); }
    // 以上兩行的用法:
    // istream_iterator<int> eof;   造成 end_marker 爲 false,所以可以當做一個流的 eof 使用
    // istream_iterator<int> initer(cin);	會引發一個 read()! 所以創建時,
    // 會一直保持着等待這個輸入
    
    reference operator*() const { return value; }
    pointer operator->() const { return &(operator*()); }
    
    // 迭代器前進一個位置就代表要讀取一次
    istream_iterator<T, Distance>& operator++() {
        read();
        return *this;
    }
    istream_iterator<T, Distance>& operator++(int) {
        istream_iterator<T, Distance> tmp = *this;
        read();
        return tmp;
    }
};

​ 所以我們配合插入迭代器和 copy 函數,可以很簡單的是進行輸入:

vector<int> v;
istream<int> in(cin);
istream<int> eof;
copy(in, eof, back_inserter(v));

ostream_iterator 代碼就不貼上了。主要是 重載 operator=(),而 operator*() 以及前置後置 operator++ 則沒有任何意義,直接返回 *this 即可。

仿函數配接器的就比較多,這裏不敘述了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章