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 即可。

仿函数配接器的就比较多,这里不叙述了

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