STL——iterator

1 概述

迭代器可以分为五类:输入迭代器、输出迭代器、前向迭代器、双向迭代器和随机存取迭代器。STL中用五个类来代表这五种迭代器类别:


     

如上图所示,左边的都有实现右边的功能,有点类似于继承,但他们不是用继承来实现的

The characteristics of each category of iterators are:

category characteristic valid expressions
all categories Can be copied and copy-constructed X b(a);
b = a;
Can be incremented ++a
a++
*a++
Random Access Bidirectional Forward Input Accepts equality/inequality comparisons a == b
a != b
Can be dereferenced as an rvalue *a
a->m
Output Can be dereferenced to be the left side of an assignment operation *a = t
*a++ = t
  Can be default-constructed X a;
X()
  Can be decremented --a
a--
*a--
  Supports arithmetic operators + and - a + n
n + a
a - n
a - b
Supports inequality comparisons (<><= and >=) between iterators a < b
a > b
a <= b
a >= b
Supports compound assignment operations += and -= a += n
a -= n
Supports offset dereference operator ([]) a[n]


不同类型的迭代器功能也不一。读和写就需要使用不同的功能。随机存取对于一个”vector”既高效的又方便的,但是,对于”list”是代价高的。
不同的容器提供了不同类型的迭代器

迭代器类型 描述 提供者 标签Tag
输入(Input) 通过前移操作读取数据。 这种迭代器可以前移,可以比较,也可以解除引用。 istream input_iterator_tag
输出(Output) 通过前移动作写入数据。 这种迭代器可以前移,也可以解除引用。 ostream, inserter output_iterator_tag
前向(Forward) 通过前移操作读写数据。结合了输入迭代器和输出迭代器的功能,能够存储迭代器的值。 slist forward_iterator_tag
双向(Bidirectional) 通过前移操作和后移操作读写数据。这些迭代器类似于前向迭代器,但是,可以对其进行前移或者后移。 list, map, multimap, set, multiset bidirectional_iterator_tag
随机存取(Random-access) 随机读写数据,是功能最强的迭代器,结合了双向迭代器的功能,能够进行指针算术运算和指针比较运算。 array, deque, string, vector random_access_iterator_tag

每个STL容器都关联一类迭代器,每个STL 算法均使用一定类型的迭代器。 每种容器都会有iterator , const_iterator,至于所属的类型要由具体的容器决定,如vector里面的iterator是random_access_iterator

迭代器定义如下

template <class Category, class T, class Distance = ptrdiff_t,
          class Pointer = T*, class Reference = T&>
  struct iterator {
    typedef T         value_type;
    typedef Distance  difference_type;
    typedef Pointer   pointer;
    typedef Reference reference;
    typedef Category  iterator_category;
  };

  value_type: 代表迭代器所指对象的类型。

  difference_type:代表两个迭代器之间的距离

  reference_type:代表迭代器所指对象的引用类型。简言之,它是operator*()的返回类型

  pointer_type:代表迭代器所致对象的指针类型。简言之,它是operator->()的返回类型

  iterator_category:代表1中提出的五种迭代器的类型标识

begin 和 end的位置



2 iterator_traits

为了方便算法的使用,iterator_traits会将每种容器定义的五种类型萃取出来:

复制代码
1 template <class _Iterator>
2 struct iterator_traits {
3   typedef typename _Iterator::iterator_category iterator_category;
4   typedef typename _Iterator::value_type        value_type;
5   typedef typename _Iterator::difference_type   difference_type;
6   typedef typename _Iterator::pointer           pointer;
7   typedef typename _Iterator::reference         reference;
8 };
复制代码

iterator_traits扮演了类似于下图的一个角色:

   iterator_traits为屏蔽了下层各容器类型的不同,为上层的应用(主要是一些算法,如advance()等)提供了统一的用户界面。

如我们要实现一个模板的find函数,因为我们不知道要返回什么类型,所以可以用iterator_traits

template <typename iter, typename T>

iterator_traits<T>::value_type find(iter begin, iter end, T& value);


3 迭代器的适配器

STL提供了许多基于迭代器的适配器,如back_insert_iterator, front_insert_iterator, inser_iterator, reverse_iterator, istream_iterator, ostream_iterator, istreambuf_iterator, ostreambuf_iterator等。

  这些适配器大致可以分为三类:插入迭代器、反向迭代器和IO迭代器。下面一一介绍这三类迭代器,重点会放在反向迭代器上。

  3.1 插入迭代器

    插入迭代器用于将值插入到容器中。插入迭代器是一个模板类,模板参数为容器,迭代器只需要在重载操作符函数operator=()中调用容器的插入操作(对应的push_back, push_front或insert)即可。   

insert_iterator实现

     为什么需要插入迭代器呢,因为对于copy函数,并没有为destination申请空间,如果空间不足就会导致不可预料的结果,而使用插入迭代器就可以解决这个问题,他可以使得destination的空间相应的增长。

    back_insert :只有提供push_back的容器才能使用,如vector,deque,list

    front_insert: 只有提供push_front的容器才能使用,如 deque,list

    inserters: 所有类型的容器都可以使用,对于associative容器,只能用这个,并且pos指定为begin,容器会根据值的大小找相应的位置插入

  3.2 反向迭代器

    顾名思义,反向迭代器会提供与普通迭代器相反方向的遍历功能。反向迭代器其实一个正向迭代器的适配器,它的实现都是通过调用正向迭代器的操作,为了与迭代器的概念保持一致(begin指向迭代器的第一个元素,end指向迭代器的最后一个元素的下一个位置),又与正向迭代器有一点点不同。

    reverse_iterator的实现中有一个名为current的Iterator,它是模板参数,即正向迭代器。正向迭代器指向的范围是序列中的第一个元素到最后一个元素的下一个位置,为了保持迭代器概念的统一,反向迭代器的rbegin应该是序列的最后一个元素,rend应该是第一个元素前面的元素。

    所以,current总是指向reverse_iterator所指元素之后的一个元素。这也意味这*返回的是值*(current-1),++通过对current的--实现。下面贴上reverse_iterator的代码。  

 1 template <class _Iterator>
 2 class reverse_iterator 
 3 {
 4 protected:
 5   _Iterator current;
 6 public:
 7   typedef typename iterator_traits<_Iterator>::iterator_category
 8           iterator_category;
 9   typedef typename iterator_traits<_Iterator>::value_type
10           value_type;
11   typedef typename iterator_traits<_Iterator>::difference_type
12           difference_type;
13   typedef typename iterator_traits<_Iterator>::pointer
14           pointer;
15   typedef typename iterator_traits<_Iterator>::reference
16           reference;
17 
18   typedef _Iterator iterator_type;
19   typedef reverse_iterator<_Iterator> _Self;
20 
21 public:
22   reverse_iterator() {}
23   explicit reverse_iterator(iterator_type __x) : current(__x) {}
24 
25   reverse_iterator(const _Self& __x) : current(__x.current) {}
26 #ifdef __STL_MEMBER_TEMPLATES
27   template <class _Iter>
28   reverse_iterator(const reverse_iterator<_Iter>& __x)
29     : current(__x.base()) {}
30 #endif /* __STL_MEMBER_TEMPLATES */
31     
32   iterator_type base() const { return current; }
33   reference operator*() const {
34     _Iterator __tmp = current;
35     return *--__tmp;
36   }
37 #ifndef __SGI_STL_NO_ARROW_OPERATOR
38   pointer operator->() const { return &(operator*()); }
39 #endif /* __SGI_STL_NO_ARROW_OPERATOR */
40 
41   _Self& operator++() {
42     --current;
43     return *this;
44   }
45   _Self operator++(int) {
46     _Self __tmp = *this;
47     --current;
48     return __tmp;
49   }
50   _Self& operator--() {
51     ++current;
52     return *this;
53   }
54   _Self operator--(int) {
55     _Self __tmp = *this;
56     ++current;
57     return __tmp;
58   }
59 
60   _Self operator+(difference_type __n) const {
61     return _Self(current - __n);
62   }
63   _Self& operator+=(difference_type __n) {
64     current -= __n;
65     return *this;
66   }
67   _Self operator-(difference_type __n) const {
68     return _Self(current + __n);
69   }
70   _Self& operator-=(difference_type __n) {
71     current += __n;
72     return *this;
73   }
74   reference operator[](difference_type __n) const { return *(*this + __n); }  
75 }; 

 

  3.3 IO迭代器

  标准库提供4个迭代器类型,以使流能够融入容器和算法的框架中:

  ostream_iterator: 用于向ostream中写入

  istream_iterator: 用于向istream中读出

  ostreambuf_iterator: 用于向流缓冲区写入

  istreambuf_iterator: 用于从流缓冲区读出

  输入输出迭代器的思想是将输入输出流当作序列,ostream_iterator和istream_iterator相当于指向序列的迭代器,用户可以通过这个迭代器对输入输出流做操作。但是,ostream_iterator的迭代器类型是input_iterator,只支持写操作(*p=X)和迭代操作(++);istream_iterator的迭代器类型是output_iterator,它可以支持读(=*p), 访问(->),迭代(++),比较(==, !=)操作

  下面的代码是ostream_iterator的实现代码:

 1 template <class _Tp,
 2           class _CharT = char, class _Traits = char_traits<_CharT> >
 3 class ostream_iterator {
 4 public:
 5   typedef _CharT                         char_type;
 6   typedef _Traits                        traits_type;
 7   typedef basic_ostream<_CharT, _Traits> ostream_type;
 8 
 9   typedef output_iterator_tag            iterator_category;
10   typedef void                           value_type;
11   typedef void                           difference_type;
12   typedef void                           pointer;
13   typedef void                           reference;
14 
15   ostream_iterator(ostream_type& __s) : _M_stream(&__s), _M_string(0) {}
16   ostream_iterator(ostream_type& __s, const _CharT* __c) 
17     : _M_stream(&__s), _M_string(__c)  {}
18   ostream_iterator<_Tp>& operator=(const _Tp& __value) { 
19     *_M_stream << __value;
20     if (_M_string) *_M_stream << _M_string;
21     return *this;
22   }
23   ostream_iterator<_Tp>& operator*() { return *this; }
24   ostream_iterator<_Tp>& operator++() { return *this; } 
25   ostream_iterator<_Tp>& operator++(int) { return *this; } 
26 private:
27   ostream_type* _M_stream;
28   const _CharT* _M_string;
29 };

 

  用户可以像下面一样使用ostream_iterator:

1     ostream_iterator<string> os(cout);
2     *++os = "cobb";
3     *os = "liu";

  上面的这段程序会产生输出cobbliu。在使用ostream_iterator的时候需要像使用正常迭代器一样将迭代器作迭代操作(++)。

  istream_iterator的实现跟ostream_iterator的实现大相径庭,值得注意的是istream_iterator中有一个标志标识输入序列是否结束,它的默认构造函数会将istream_iterator指向输入序列的结束位置(M_ok=false),表示输入序列结束。当对输入迭代器作迭代操作(++)的时候,会判断M_ok的值,如果该值为false,则终止读过程。

  

  istreambuf_iterator和ostreambuf_iterator可以使用户跨过iostream,直接跟流缓冲区打交道。


4  其他

++iter 比 ++iter要快,因为前者返回的是新的值,不需要存储旧的值;后者返回的是旧的值,要把旧的值存储起来

几个有用的函数,#include <iterator>

void advance (InputIterator& pos, Dist n) ,可以向前或向后移动n,对非random iterator也适用的

Dist distance (InputIterator pos1, InputIterator pos2) 

#include <algorithm> 
void iter_swap (ForwardIterator1 pos1, ForwardIterator2 pos2) //pos1,pos2的类型可以不一样,但其值必须是可相互赋值的


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值