标准库--迭代器

1.概述

c++标准库标准库实现了很多容器,容器的使用过程中我们有基于容器位置获取或设置位置元素,位置前进或后退,位置比较的需求。将这类容器位置相关的需求封装起来就是迭代器。

c++标准库容器有很多,不同的容器对位置的管理有不同的要求,如数组可以直接依据索引到达目标位置,而链表只能逐个前进到达目标位置。为了对这些不同的位置管理进行抽象分类。标准库最终定义了五类迭代器。

这五类迭代器分别用以下类别来表示

struct input_iterator_tag {};
struct output_iterator_tag {};
struct forward_iterator_tag : public input_iterator_tag {};
struct bidirectional_iterator_tag : public forward_iterator_tag {};
struct random_access_iterator_tag : public bidirectional_iterator_tag {};

c++基于模板实现泛型编程,不像java基于接口实现。模板中对模板类型参数的要求没办法通过明确的类型定义给出来,只能通过约定熟成的方式希望类的使用者,实现者都明白来保证正确性。

泛型的好处是,对于类型定义,一个定义实现可以适用于多种模板参数类型,比如charint可以共用一份vector模板实现。对于模板函数也是如此。但其中隐藏的陷进是类的实现者,类的使用者必须就模板实现中对模板类型的要求达成约定熟成的一致观点。

当我们要使用或实现对应类别的迭代器时,我们必须要清楚每种类别的迭代器实现上的要求。

2. input_iterator_tag 类别迭代器

2.1.迭代器的规范
input_iterator_tag 迭代器是一种单向迭代器,只能向前遍历序列,且不能后退。
input_iterator_tag 迭代器的规范:

class InputIterator {  
public:  
    using value_type = ...; // 假设我们正在迭代整数  
    using reference = ...;  
    using pointer = ...;  
    using difference_type = ...;  
    using iterator_category = std::input_iterator_tag; // 这是输入迭代器的类别标签  
    InputIterator(...) : ... {}  
    InputIterator& operator++() { // 前置 ++  
        ...
    }  
  
    bool operator==(const InputIterator& other) const { // 相等运算符  
        ...
    }  
    bool operator!=(const InputIterator& other) const { // 不等运算符  
        ...
    }  
    const reference operator*() const { // 解引用运算符  
        ... 
    }  
};

如上所示,对input_iterator_tag 类别的迭代器的实现要求是:
(1). 迭代器类型内部需定义value_typereferencepointerdifference_typeiterator_category内部类型。
a. value_type 一般表示迭代位置的元素的值类型。
b. reference 一般表示值类型的引用。
c. pointer 一般表示值的指针。
d. difference_type ,一般表示两个位置间差值。
e. iterator_category,迭代器类别。这里应该固定为input_iterator_tag
(2). 迭代器类型应该提供前置++
(3). 允许对迭代器iter实例执行*iter来访问所在位置的元素。上述实例中operator*()返回const reference使得其恰好满足input_iterator_tag迭代器的要求,但若某个input_iterator_tag实现返回reference也是可以的。这时,这个实现既满足input_iterator_tag要求,又在要求的基础上提供了进一步的功能扩展。但以input_iterator_tag类别参与泛型编程时, 使用者对input_iterator_tag实例的预期应该是可执行*iter获得迭代器位置下的值,不应持有*iter=value;的预期。
(4). 迭代器类型应该提供==!=运算符。

2.2.标准库中的实例

template<typename _Category, typename _Tp, typename _Distance = ptrdiff_t, typename _Pointer = _Tp*, typename _Reference = _Tp&>
struct iterator
{
    typedef _Category  iterator_category;
    typedef _Tp        value_type;
    typedef _Distance  difference_type;
    typedef _Pointer   pointer;
    typedef _Reference reference;
};

template<typename _Tp, typename _CharT = char, typename _Traits = char_traits<_CharT>, typename _Dist = ptrdiff_t>
class istream_iterator : public iterator<input_iterator_tag, _Tp, _Dist, const _Tp*, const _Tp&>
{
public:
    typedef _CharT                         char_type;
    typedef _Traits                        traits_type;
    typedef basic_istream<_CharT, _Traits> istream_type;
private:
    istream_type*	_M_stream;
    _Tp		        _M_value;
    bool		    _M_ok;
public:
    istream_iterator(istream_type& __s) : _M_stream(&__s) { _M_read(); }
    const _Tp& operator*() const {
        return _M_value;
    }
    istream_iterator& operator++() {
        _M_read();
        return *this;
    }
    istream_iterator operator++(int) {
        istream_iterator __tmp = *this;
        _M_read();
        return __tmp;
    }
    const _Tp* operator->() const { return &(operator*()); }
    bool _M_equal(const istream_iterator& __x) const { 
    	return (_M_ok == __x._M_ok) && (!_M_ok || _M_stream == __x._M_stream); 
    }

private:
    void _M_read() {
        _M_ok = (_M_stream && *_M_stream) ? true : false;
        if (_M_ok) {
            *_M_stream >> _M_value;
            _M_ok = *_M_stream ? true : false;
        }
    }
};

template<typename _Tp, typename _CharT, typename _Traits, typename _Dist>
inline bool operator==(const istream_iterator<_Tp, _CharT, 
	_Traits, _Dist>& __x, const istream_iterator<_Tp, _CharT, _Traits, _Dist>& __y)
{ return __x._M_equal(__y); }
template <class _Tp, class _CharT, class _Traits, class _Dist>
inline bool operator!=(const istream_iterator<_Tp, _CharT, 
	_Traits, _Dist>& __x, const istream_iterator<_Tp, _CharT, _Traits, _Dist>& __y)
{ return !__x._M_equal(__y); }

忽略无关部分,我们来检查该实现对规范的遵循情况:
(1). 迭代器类型内部需定义value_typereferencepointerdifference_typeiterator_category内部类型。
上述实现通过公共继承iterator来完成此项工作。
(2). 迭代器类型应该提供前置++运算符。
(3). 允许对迭代器iter实例执行*iter来访问所在位置的元素。
因为是输入迭代器,这里返回的const _Tp&类型使得使用者针对该迭代器只能执行xxx = *iter,无法执行*iter = xxx;
(4). 迭代器类型应该提供==!=运算符

3. output_iterator_tag 类别迭代器

3.1.迭代器规范
output_iterator_tag 迭代器的规范:

#include   
#include     
class MyOutputIterator {  
public:  
    using iterator_category = std::output_iterator_tag;  
    using value_type = xxx;  
    using difference_type = xxx;  
    using pointer = xxx;  
    using reference = xxx;  
    MyOutputIterator(xxx) : ... {}  
    MyOutputIterator& operator=(const value_type & value) {  
       ...
    }  
    MyOutputIterator& operator*() {  
        ...  
    }  
    MyOutputIterator& operator++() {  
        ...  
    }  
    MyOutputIterator operator++(int) {  
        ...  
    }  
  	...
};

(1). 需要定义以下内部类别
iterator_category,必须固定为std::output_iterator_tag
value_type ,一般为迭代器位置下的值类型。
difference_type ,用于表示两个迭代器位置的差值。
pointer,一般为迭代器位置。
reference,一般为值的引用。
(2). 运算符重载,需要重载前置++
(3). 对迭代器实例iter,支持*iter=value;来设置位置下的值。

input_iterator_tag 类别迭代器区别:
(1). input_iterator_tag迭代器类别强调的是通过*iter来访问位置下的值,output_iterator_tag强调的是通过*iter=value;来设置位置下的值。
(2). input_iterator_tag额外强调了==!=output_iterator_tag额外强调了后置++

3.2.标准库中实例

#define __PTRDIFF_TYPE__ long int
typedef __SIZE_TYPE__ 	size_t;
typedef __PTRDIFF_TYPE__	ptrdiff_t;
template<typename _Category, typename _Tp, typename _Distance = ptrdiff_t, typename _Pointer = _Tp*, typename _Reference = _Tp&>
struct iterator
{
    typedef _Category  iterator_category;
    typedef _Tp        value_type;
    typedef _Distance  difference_type;
    typedef _Pointer   pointer;
    typedef _Reference reference;
};

template<typename _Container>
class back_insert_iterator : public iterator<output_iterator_tag, void, void, void, void>
{
protected:
    _Container* container;

public:
    typedef _Container          container_type;
    explicit back_insert_iterator(_Container& __x) : container(&__x) { }
#if __cplusplus < 201103L
    back_insert_iterator& operator=(typename _Container::const_reference __value)
    {
        container->push_back(__value);
        return *this;
    }
#else
    back_insert_iterator& operator=(const typename _Container::value_type& __value)
    {
        container->push_back(__value);
        return *this;
    }

    back_insert_iterator& operator=(typename _Container::value_type&& __value)
    {
        container->push_back(std::move(__value));
        return *this;
    }
#endif

    back_insert_iterator& operator*()
    { return *this; }

    back_insert_iterator& operator++()
    { return *this; }

    back_insert_iterator operator++(int)
    { return *this; }
};

忽略无关部分,我们来检查该实现对规范的遵循情况:
(1). 迭代器类型内部需定义value_typereferencepointerdifference_typeiterator_category内部类型。
上述实现通过公共继承iterator来完成此项工作。
(2). 迭代器类型应该提供前置++
(3). 允许对迭代器iter实例执行*iter=value来设置所在位置的元素。
(4). 迭代器类型应该提供后置++

4. forward_iterator_tag类别迭代器

4.1. 迭代器规范
forward_iterator_tag迭代器规范:

class MyForwardIterator {  
public:  
    using iterator_category = std::forward_iterator_tag;  
    using value_type = xxx;  
    using difference_type = xxx;  
    using pointer = xxx;  
    using reference = xxx;  
    MyForwardIterator(xxx) : ... {}  
    MyForwardIterator& operator++() {  
        ...  
    }  
  
    bool operator==(const MyForwardIterator& other) const {  
        ...  
    }  
    bool operator!=(const MyForwardIterator& other) const {  
        ...  
    }  
    reference operator*() const {  
        ...  
    }  
 	...
};

如上所示,对forward_iterator_tag 类别的迭代器的实现要求是:
(1). 迭代器类型内部需定义value_typereferencepointerdifference_typeiterator_category内部类型。
a. value_type 一般表示迭代位置的元素的值类型。
b. reference 一般表示值类型的引用。
c. pointer 一般表示值的指针。
d. difference_type ,一般表示两个位置间差值。
e. iterator_category,迭代器类别。这里应该固定为forward_iterator_tag
(2). 迭代器类型应该提供前置++==!=运算符。
(3). 允许对迭代器iter实例执行*iter来访问所在位置的元素。
(4). 允许对迭代器iter实例执行*iter = value来设置所在位置的元素。

input_iterator_tag 类别迭代器区别:
a. forward_iterator_tag其实就是input_iterator_tag+(4)

4.2.标准库中的实例

template<typename _Tp>
struct _Fwd_list_iterator
{
    typedef _Fwd_list_iterator<_Tp>            _Self;
    typedef _Fwd_list_node<_Tp>                _Node;
    typedef _Tp                                value_type;
    typedef _Tp*                               pointer;
    typedef _Tp&                               reference;
    typedef ptrdiff_t                          difference_type;
    typedef std::forward_iterator_tag          iterator_category;
    _Fwd_list_iterator() : _M_node() { }

    explicit _Fwd_list_iterator(_Fwd_list_node_base* __n) : _M_node(__n) { }

    reference operator*() const
    { return *static_cast<_Node*>(this->_M_node)->_M_valptr(); }

    _Self& operator++()
    {
        _M_node = _M_node->_M_next;
        return *this;
    }

    _Self operator++(int)
    {
        _Self __tmp(*this);
        _M_node = _M_node->_M_next;
        return __tmp;
    }

    bool operator==(const _Self& __x) const
    { return _M_node == __x._M_node; }

    bool operator!=(const _Self& __x) const
    { return _M_node != __x._M_node; }

    pointer operator->() const
    { return static_cast<_Node*>(this->_M_node)->_M_valptr(); }
    
    _Self _M_next() const
    {
        if (_M_node)
            return _Fwd_list_iterator(_M_node->_M_next);
        else
            return _Fwd_list_iterator(0);
    }

    _Fwd_list_node_base* _M_node;
};

忽略无关部分,我们来检查该实现对规范的遵循情况:
(1). 迭代器类型内部需定义value_typereferencepointerdifference_typeiterator_category内部类型。
(2). 迭代器类型应该提供前置++==!=运算符。。
(3). 允许对迭代器iter实例执行*iter来访问所在位置的元素。
(4). 允许对迭代器iter实例执行*iter=value来设置所在位置的元素。

5. bidirectional_iterator_tag 类别迭代器

5.1.迭代器规范

class MyBidirectionalIterator {  
public:  
    using iterator_category = std::bidirectional_iterator_tag;  
    using value_type = xxx;  
    using difference_type = xxx;  
    using pointer = xxx;  
    using reference = xxx;  
    MyBidirectionalIterator(...) : ... {}  
    MyBidirectionalIterator& operator++() {  
        ...
    }  
   
    MyBidirectionalIterator& operator--() {  
        ...  
    }
   
    bool operator==(const MyBidirectionalIterator& other) const {  
        ... 
    }  
    bool operator!=(const MyBidirectionalIterator& other) const {  
        ...  
    }  
    reference operator*() const {  
        ...  
    }  
	...  
};

如上所示,对bidirectional_iterator_tag 类别的迭代器的实现要求是:
(1). 迭代器类型内部需定义value_typereferencepointerdifference_typeiterator_category内部类型。
a. value_type 一般表示迭代位置的元素的值类型。
b. reference 一般表示值类型的引用。
c. pointer 一般表示值的指针。
d. difference_type ,一般表示两个位置间差值。
e. iterator_category,迭代器类别。这里应该固定为bidirectional_iterator_tag
(2). 迭代器类型应该提供前置++==!=运算符。
(3). 允许对迭代器iter实例执行*iter来访问所在位置的元素。
(4). 允许对迭代器iter实例执行*iter = value来设置所在位置的元素。
(5). 迭代器类型应该提供前置--

forward_iterator_tag 类别迭代器区别:
a. bidirectional_iterator_tag 其实就是forward_iterator_tag+(5)

5.2.标准库中实例

template<typename _Tp>
struct _List_iterator
{
    typedef _List_iterator<_Tp>                _Self;
    typedef _List_node<_Tp>                    _Node;
    typedef ptrdiff_t                          difference_type;
    typedef std::bidirectional_iterator_tag    iterator_category;
    typedef _Tp                                value_type;
    typedef _Tp*                               pointer;
    typedef _Tp&                               reference;
    
    _List_iterator() : _M_node() { }
    explicit _List_iterator(__detail::_List_node_base* __x) : _M_node(__x) { }
    reference operator*() const
    { return static_cast<_Node*>(_M_node)->_M_data; }

    _Self& operator++()
    {
        _M_node = _M_node->_M_next;
        return *this;
    }

    _Self operator++(int)
    {
        _Self __tmp = *this;
        _M_node = _M_node->_M_next;
        return __tmp;
    }

    _Self& operator--()
    {
        _M_node = _M_node->_M_prev;
        return *this;
    }
    _Self operator--(int)
    {
        _Self __tmp = *this;
        _M_node = _M_node->_M_prev;
        return __tmp;
    }

    bool operator==(const _Self& __x) const
    { return _M_node == __x._M_node; }

    bool operator!=(const _Self& __x) const
    { return _M_node != __x._M_node; }

    pointer operator->() const
    { return std::__addressof(static_cast<_Node*>(_M_node)->_M_data); }

    __detail::_List_node_base* _M_node;
};

忽略无关部分,我们来检查该实现对规范的遵循情况:
(1). 迭代器类型内部需定义value_typereferencepointerdifference_typeiterator_category内部类型。
(2). 迭代器类型应该提供前置++
(3). 允许对迭代器iter实例执行*iter来访问所在位置的元素。
(4). 允许对迭代器iter实例执行*iter=value来设置所在位置的元素。
(5). 迭代器类型应该提供前置--

6. random_access_iterator_tag 类别迭代器

6.1.迭代器规范

class MyRandomAccessIterator {  
public:  
    using iterator_category = std::random_access_iterator_tag;  
    using value_type = xxx;  
    using difference_type = xxx;  
    using pointer = xxx;  
    using reference = xxx;  
    MyRandomAccessIterator(...) : ... {}  
    MyRandomAccessIterator& operator++() {  
        ...  
    }  
    MyRandomAccessIterator& operator--() {  
        ...  
    }  
    bool operator==(const MyRandomAccessIterator& other) const {  
        ...  
    }  
    bool operator!=(const MyRandomAccessIterator& other) const {  
        ...  
    }  
    reference operator*() const {  
        ...  
    }  
    MyRandomAccessIterator operator+(difference_type n) const {  
        ...  
    }  
    MyRandomAccessIterator& operator+=(difference_type n) {  
        ...  
    }  
    MyRandomAccessIterator operator-(difference_type n) const {  
        ...  
    }  
    MyRandomAccessIterator& operator-=(difference_type n) {  
        ...  
    }  
    difference_type operator-(const MyRandomAccessIterator& other) const {  
        ...  
    }  
 	...  
};

如上所示,对random_access_iterator_tag 类别的迭代器的实现要求是:
(1). 迭代器类型内部需定义value_typereferencepointerdifference_typeiterator_category内部类型。
a. value_type 一般表示迭代位置的元素的值类型。
b. reference 一般表示值类型的引用。
c. pointer 一般表示值的指针。
d. difference_type ,一般表示两个位置间差值。
e. iterator_category,迭代器类别。这里应该固定为random_access_iterator_tag
(2). 迭代器类型应该提供前置++,前置--==!=运算符。
(3). 允许对迭代器iter实例执行*iter来访问所在位置的元素。
(4). 允许对迭代器iter实例执行*iter = value来设置所在位置的元素。
(5). 迭代器类型应该提供前置--运算符。
(6). 迭代器类型应提供+,-,+=,-=运算符以支持强化的前移,后移,迭代器相减。

random_access_iterator_tag 类别迭代器区别:
a. random_access_iterator_tag 其实就是random_access_iterator_tag +(6)

6.2.标准库实例

template<typename _Iterator, typename _Container>
class __normal_iterator
{
protected:
    _Iterator _M_current;
    typedef iterator_traits<_Iterator>		__traits_type;

public:
    typedef _Iterator					iterator_type;
    typedef typename __traits_type::iterator_category iterator_category;
    typedef typename __traits_type::value_type  	value_type;
    typedef typename __traits_type::difference_type 	difference_type;
    typedef typename __traits_type::reference 	reference;
    typedef typename __traits_type::pointer   	pointer;
    _GLIBCXX_CONSTEXPR __normal_iterator() : _M_current(_Iterator()) { }
    explicit __normal_iterator(const _Iterator& __i) : _M_current(__i) { }
    template<typename _Iter>
    __normal_iterator(const __normal_iterator<_Iter, typename __enable_if<(std::__are_same<_Iter, typename _Container::pointer>::__value), _Container>::__type>& __i)
    : _M_current(__i.base()) { }

    reference operator*() const
    { return *_M_current; }

    pointer operator->() const
    { return _M_current; }

    __normal_iterator& operator++()
    {
        ++_M_current;
        return *this;
    }

    __normal_iterator operator++(int)
    { return __normal_iterator(_M_current++); }

    __normal_iterator& operator--()
    {
        --_M_current;
        return *this;
    }

    __normal_iterator operator--(int)
    { return __normal_iterator(_M_current--); }

    reference operator[](const difference_type& __n) const
    { return _M_current[__n]; }

    __normal_iterator& operator+=(const difference_type& __n)
    { _M_current += __n; return *this; }

    __normal_iterator operator+(const difference_type& __n) const
    { return __normal_iterator(_M_current + __n); }

    __normal_iterator& operator-=(const difference_type& __n)
    { _M_current -= __n; return *this; }

    __normal_iterator operator-(const difference_type& __n) const
    { return __normal_iterator(_M_current - __n); }

    const _Iterator& base() const
    { return _M_current; }
};

忽略无关部分,我们来检查该实现对规范的遵循情况:
(1). 迭代器类型内部需定义value_typereferencepointerdifference_typeiterator_category内部类型。
(2). 迭代器类型应该提供前置++
(3). 允许对迭代器iter实例执行*iter来访问所在位置的元素。
(4). 允许对迭代器iter实例执行*iter=value来设置所在位置的元素。
(5). 迭代器类型应该提供前置--
(6). 迭代器类型应该提供+,+=,-,-=以支持强化的前移,后移,迭代器相减。

你可能感兴趣的:(1.4.语言-C++标准库,input_iterator,output_iterator,forward_iter,bidirec_iter,random_iter,迭代器)