C++迭代器适配器:反向迭代器、插入迭代器、iostream迭代器


适配器是标准库中的一个通用概念。容器、迭代器和函数都有适配器(C++11出现了lambda函数、function类模板、bind函数,几乎取代了函数适配器)。本质上,适配器是一种机制,能使某种事物的行为看起来像另外一种一样。栈、队列、优先队列都属于容器适配器。本文主要介绍迭代器适配器。

迭代器适配器主要有三类:反向迭代器,插入迭代器,iostream迭代器。

插入迭代器

插入迭代器有三种类型,差异在于元素插入的位置:

  • back_inserter( Container& c ),在容器尾部插入,只能对有push_back()的容器使用
  • inserter( Container& c, Container::iterator i ),在容器内部指定迭代器前插入,只能对有insert()的容器使用。
  • front_inserter( Container& c ),在容器头部插入,只能对有push_front()的容器使用。

假如你不能确定容器的大小,使用这三种迭代器,可以保证了不会造成越界的情况。

vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
fill_n(inserter(v, v.begin() + 1), 3, -2);  // v:1 -2 -2 -2 2 3 4 5 6 7 8 9 10 

vector<int> v2;
copy(v.begin(),v.end(),back_inserter(v2));  // v2:1 -2 -2 -2 2 3 4 5 6 7 8 9 10 

deque<int> d;
copy(v.begin(),v.end(),front_inserter(d));  //逆序插入 d:10 9 8 7 6 5 4 3 2 -2 -2 -2 1

原理分析

每一个insert iterators 内部都维护有一个容器(必须由用户指定);容器当然有自己的迭代器,于是,当客户端对insert iterators做赋值(assign)操作时,就在insert iterators中被转为对该容器的选代器做插入操作,也就是说,在insert iterators的operator=操作符中调用底层容器的push_front()或push_back()或insert()操作函数。至于其它的迭代器惯常行为如operator++operator++(int)operator*都被关闭功能,更没有提供operator--(int)operator--operator->等功能。换句话说,insert iterators的前进、后退、取值、成员取用等操作都是没有意义的,甚至是不允许的。
下面是back_inserter源码:

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;
 
  explicit back_insert_iterator(Container& x) : container(&x) {}
 
  // 只有提供了push_back()操作的容器才能使用back_insert_iterator
  back_insert_iterator<Container>&
  operator=(const typename Container::value_type& value)
  {
    container->push_back(value);
    return *this;
  }
 
  back_insert_iterator<Container>& operator*() { return *this; }
  back_insert_iterator<Container>& operator++() { return *this; }
  back_insert_iterator<Container>& operator++(int) { return *this; }
};

反向迭代器

反向迭代器就是将迭代器的移动行为倒转。如果STL算法接受的不是一般正常的迭代器,而是这种逆向迭代器,它就会以从尾到头的方向来处理序列中的元素。例如:

//将所有元素逆向拷贝到ite所指位置上
//rbegin()和rend()返回的就是反向迭代器
copy(id.rbegin(),id.rend(),ite);

id.rbegin().base()返回反向迭代器对应的正向迭代器id.end()

rbegin()虽然对应于原迭代器的end(),但是逆向迭代器的operator* 被重载为将"对应的正向迭代器后退一格而后取值",因此*id.rbegin()返回容器尾部元素值。这么做是为了配合迭代器区间左闭右开的习惯,使其不用额外修改就能搭配原有的STL函数。

在这里插入图片描述
实线表示取值*时对应的迭代器,虚线表示实际对应的迭代器。

template <class Iterator>
class reverse_iterator
{
protected:
  Iterator current;
public:
  typedef typename iterator_traits<Iterator>::iterator_category
          iterator_category;
  typedef typename iterator_traits<Iterator>::value_type
          value_type;
  typedef typename iterator_traits<Iterator>::difference_type
          difference_type;
  typedef typename iterator_traits<Iterator>::pointer
          pointer;
  typedef typename iterator_traits<Iterator>::reference
          reference;
 
  typedef Iterator iterator_type;
  typedef reverse_iterator<Iterator> self;
 
public:
  reverse_iterator() {}
  explicit reverse_iterator(iterator_type x) : current(x) {}
 
  reverse_iterator(const self& x) : current(x.current) {}
#ifdef __STL_MEMBER_TEMPLATES
  template <class Iter>
  reverse_iterator(const reverse_iterator<Iter>& x) : current(x.current) {}
#endif /* __STL_MEMBER_TEMPLATES */
 
  iterator_type base() const { return current; }
  reference operator*() const {
    Iterator tmp = current;
    return *--tmp;
  }
#ifndef __SGI_STL_NO_ARROW_OPERATOR
  pointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */
 
  self& operator++() {
    --current;
    return *this;
  }
  self operator++(int) {
    self tmp = *this;
    --current;
    return tmp;
  }
  self& operator--() {
    ++current;
    return *this;
  }
  self operator--(int) {
    self tmp = *this;
    ++current;
    return tmp;
  }
 
  self operator+(difference_type n) const {
    return self(current - n);
  }
  self& operator+=(difference_type n) {
    current -= n;
    return *this;
  }
  self operator-(difference_type n) const {
    return self(current + n);
  }
  self& operator-=(difference_type n) {
    current += n;
    return *this;
  }
  reference operator[](difference_type n) const { return *(*this + n); }
};

iostream迭代器

  • istream_iterator(),输入迭代器,可以对istream对象进行操作
  • ostream_iterator(),输出迭代器,可以对ostream对象进行操作

所谓iostream迭代器,可以将迭代器绑定到一个stream(数据流)对象身上。绑定istream对象(例如cin)者,称为istream_iterator,拥有输入能力;绑定到ostream对象(例如cout)者,称为ostream_iterator,拥有输出能力。

cout<<accumulate(istream_iterator<int>(cin),istream_iterator<int>(),0);//输出从标准输入读取的值得和

vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
ostream_iterator<int> out_iter(cout," ");//第一位参数为绑定输出流;第二位参数为输出分隔符,默认为空字符串
copy(v.begin(),v.end(),out_iter);//标准输出1 2 3 4 5 6 7 8 9 10

数组输出:

copy(arr.begin(), arr.end(), ostream_iterator<int>(cout," "));

原理分析

  • istream迭代器

所谓绑定一个istream object,其实就是在istream_iterator内部维护一个istream member,客户端对于这个迭代器所做的operator++操作,会被导引调用迭代器内部所含的那个istream member的输入操作(operator>>)。这个迭代器是个Input iterator,不具备operator- -。如下是可读性比较强的一种源码版本。

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;//是否继续输入,结束为false,继续为true
  void read() {//读取输入流
    end_marker = (*stream) ? true : false;
    if (end_marker) *stream >> value;
    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) {}//使用默认构造时,读取标记关闭,不再读取,相当于eof
  istream_iterator(istream& s) : stream(&s) { read(); }//绑定时已开始读取
  reference operator*() const { return value; }        //返回输入的数据
#ifndef __SGI_STL_NO_ARROW_OPERATOR
  pointer operator->() const { return &(operator*()); }
#endif /* __SGI_STL_NO_ARROW_OPERATOR */
  istream_iterator<T, Distance>& operator++() {
    read();
    return *this;
  }
  istream_iterator<T, Distance> operator++(int)  {
    istream_iterator<T, Distance> tmp = *this;
    read();
    return tmp;
  }
};

在这里插入图片描述

  • ostream迭代器

所谓绑定一个ostream object,就是在其内部维护一个ostream member,客户端对于这个迭代器所做的 operator=操作,会被导引调用对应的(迭代器内部所含的)那个ostream member的输出操作(operator<<).这个迭代器是个Oufputterator.下面的源代码和注释说明了一切。

至于ostream iterator,所谓绑定一个ostream object,就是在其内部维护一个ostream member,客户端对于这个迭代器所做的 operator=操作,会被导引调用对应的(迭代器内部所含的)那个ostream member的输出操作(operator<<)。这个迭代器是个Output iterator。

template <class T>
class ostream_iterator
{
protected:
  ostream* stream;
  const char* string;
public:
  typedef output_iterator_tag iterator_category;
  typedef void                value_type;
  typedef void                difference_type;
  typedef void                pointer;
  typedef void                reference;
 
  ostream_iterator(ostream& s) : stream(&s), string(0) {}
  ostream_iterator(ostream& s, const char* c) : stream(&s), string(c)  {}
  ostream_iterator<T>& operator=(const T& value) {
    *stream << value;
    if (string) *stream << string;
    return *this;
  }
  ostream_iterator<T>& operator*() { return *this; }
  ostream_iterator<T>& operator++() { return *this; }
  ostream_iterator<T>& operator++(int) { return *this; }
};


参考:
《STL源码剖析》

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值