iterator adapter

graph LR
iterator --- reverse_iterator
iterator --- Insert_iterator
iterator --- iostream_iterator

Insert_iterator --- back_insert_iterator
Insert_iterator --- front_insert_iterator
Insert_iterator --- insert_iterator

插入迭代器:将一般迭代器的赋值操作转变为插入操作。

insert iterator

当用户对inserter iterator作赋值操作时,就在inserter iterator类中定义的operator()中调用底层容器的插入操作(push_back,push_front,insert,etc.).

以back_inserter插入迭代适配器为例:(front_inserter和inserter与该类相类似)

template <class _Container>
inline back_insert_iterator<_Container> back_inserter(_Container& __x) {
return back_insert_iterator<_Container>(__x);
}

当用户调用back_inserter函数时,函数实际返回后向插入迭代器类(back_insert_iterator)对象,并将容器参数传递给后向插入迭代器类的构造函数。

后向插入迭代器类代码(back_insert_iterator):

template <class _Container>
class back_insert_iterator {
protected:
_Container* container;
public:
typedef _Container container_type;
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) {}
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; }
};

类中有容器类指针_Container* container,指向待插入的容器。在类中定义的赋值操作符=中,调用了底层容器的push_back函数,将operator=参数__value插入到容器尾部。

类中还重载了迭代器操作符:dereference [],prefix_increment[++],post_increment[++(int)]。在其函数体中只是简单地返回当前迭代器本身(this),并未进行相应的前进等操作,说明对此类back_insert_iterator对象进行上述操作是不会产生什么效果。

结合例子分析:

#include<iostream>
#include<vector>
#include<algorithm>
#include<iterator> using namespace std; int main(){
int ia[]={1,5,3,6,4,8,9};
vector<int> ivec(ia,ia+7);
ostream_iterator<int> outite(cout," "); copy(ia,ia+3,back_inserter(ivec)); //a
copy(ivec.begin(),ivec.end(),outite);
//1 5 3 6 4 8 9 1 5 3
cout<<endl; return 0;
}

 程序中a行调用back_inserter函数,生成对ivec向量的后向迭代器对象(back_insert_iterator object),并将该对象传入到copy算法。在copy算法中将利用该对象作为函数,对容器中的对象进行处理。

 在程序中,后向迭代器对象只是被当作一个函数(functor)使用,对容器调用该对象提供的功能,而不是像传统的迭代器来访问数组中的元素,因此,对其进行dereference [*],prefix_increment[++],post_increment[++(int)]操作都不会产生什么效果。

程序的运行结果为:

1 5 3 6 4 8 9 1 5 3

reverse iterator

反向迭代器:将迭代器的移动方向倒转:前进变为后退,后退变为前进。

在某些容器类中定义反向迭代器成员,如vector:

template <class _Tp, class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >
class vector : protected _Vector_base<_Tp, _Alloc>
{
//...
typedef value_type* iterator; // vector的迭代器是普通指针
typedef const value_type* const_iterator;
typedef reverse_iterator<const_iterator> const_reverse_iterator;
typedef reverse_iterator<iterator> reverse_iterator; reverse_iterator rbegin()
{ return reverse_iterator(end()); }
const_reverse_iterator rbegin() const
{ return const_reverse_iterator(end()); }
reverse_iterator rend()
{ return reverse_iterator(begin()); }
const_reverse_iterator rend() const
{ return const_reverse_iterator(begin()); }
//...
}

在上面的代码中,该类还定义了rbegin(),rend()等函数,可以返回容器的反向迭代器。

reverse_iterator类的定义如下:

template <class _RandomAccessIterator, class _Tp, class _Reference = _Tp&,
class _Distance = ptrdiff_t>
class reverse_iterator {
typedef reverse_iterator<_RandomAccessIterator, _Tp, _Reference, _Distance>
_Self;
protected:
_RandomAccessIterator current;
public:
typedef random_access_iterator_tag iterator_category;
typedef _Tp value_type;
typedef _Distance difference_type;
typedef _Tp* pointer;
typedef _Reference reference; reverse_iterator() {}
explicit reverse_iterator(_RandomAccessIterator __x) : current(__x) {}
_RandomAccessIterator base() const { return current; }
_Reference operator*() const { return *(current - 1); }
#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+(_Distance __n) const {
return _Self(current - __n);
}
_Self& operator+=(_Distance __n) {
current -= __n;
return *this;
}
_Self operator-(_Distance __n) const {
return _Self(current + __n);
}
_Self& operator-=(_Distance __n) {
current += __n;
return *this;
}
_Reference operator[](_Distance __n) const { return *(*this + __n); }
};

迭代器的前进,后退等操作都与普通迭代器的方向相反。

  _Reference operator*() const { return *(current - 1); }

在解引用函数*定义中,函数先向前进一步,然后再对其解引用并返回,而正向迭代器则是直接解析其指向的元素。

stream iterator

流迭代器:将迭代器绑定到一个数据流(stream)对象上。包括istream_iterator和ostream_iterator。

graph LR
stream_iterator --- istream_iterator
stream_iterator --- ostream_iterator
istream_iterator -.-> istream
ostream_iterator -.-> ostream

ostream_iterator

istream iterator在类的内部有一个istream类型的指针。当用户对迭代器进行操作时,迭代器内部通过该指针指向的输入流对象,完成相应的操作。

template <class _Tp, class _Dist>
class istream_iterator {
template <class _T1, class _D1>
friend bool operator==(const istream_iterator<_T1, _D1>&,
const istream_iterator<_T1, _D1>&);
protected:
istream* _M_stream;
_Tp _M_value;
bool _M_end_marker;
void _M_read() {
_M_end_marker = (*_M_stream) ? true : false;
if (_M_end_marker) *_M_stream >> _M_value;
_M_end_marker = (*_M_stream) ? true : false;
}
public:
typedef input_iterator_tag iterator_category;
typedef _Tp value_type;
typedef _Dist difference_type;
typedef const _Tp* pointer;
typedef const _Tp& reference; istream_iterator() : _M_stream(&cin), _M_end_marker(false) {}
istream_iterator(istream& __s) : _M_stream(&__s) { _M_read(); }
reference operator*() const { return _M_value; }
pointer operator->() const { return &(operator*()); }
istream_iterator<_Tp, _Dist>& operator++() {
_M_read();
return *this;
}
istream_iterator<_Tp, _Dist> operator++(int) {
istream_iterator<_Tp, _Dist> __tmp = *this;
_M_read();
return __tmp;
}
};

类中istream类指针_M_stream实现迭代器的数据输入操作。_M_value变量保存最近输入的值。该类的默认构造函数用cin初始化_M_stream成员,并设置流输入结束符。用户也可以自己指定其他输入流(如文件流等)来初始化输入流指针成员_M_stream。

istream_iterator对象通常配合算法使用,可以用输入流完成对容器的初始化或赋值等功能。在算法中会调用istream_iterator对象的前进操作符号,而在自增操作符函数体中,调用了_M_read函数,在_M_read函数中,先判断是否到达流结尾,若未到达结尾,则调用输入流的operator>> ,将输入值赋给_M_value,并更新到达结尾状态。解引用操作符则可返回当前的最新输入值_M_value。每次对istream_iterator对象调用operator++,都会引发数据输入,并将输入值保存在缓存变量中。

ostream_iterator

ostream_iterator 类完成数据的输出操作。于istream_iterator的差别主要在赋值操作符operator=中:

  ostream_iterator<_Tp>& operator=(const _Tp& __value) {
*_M_stream << __value;
if (_M_string) *_M_stream << _M_string;
return *this;
}

每次对ostream_iterator类对象调用赋值操作时,都会将右操作数 __value输出到指定的输出流中,并输入指定的分割字符串。

ostream_iterator类中封锁了其他几个操作符的功能,使得对其进行操作失效:

  ostream_iterator<_Tp>& operator*() { return *this; }
ostream_iterator<_Tp>& operator++() { return *this; }
ostream_iterator<_Tp>& operator++(int) { return *this; }

STL 迭代器适配器(iterator adapter)的更多相关文章

  1. 疯子的算法总结(三) STL Ⅱ迭代器(iterator) + 容器

    一.迭代器(Iterator) 背景:指针可以用来遍历存储空间连续的数据结构,但是对于存储空间费连续的,就需要寻找一个行为类似指针的类,来对非数组的数据结构进行遍历. 定义:迭代器是一种检查容器内元素 ...

  2. [C++ STL] 迭代器(iterator)详解

    背景:指针可以用来遍历存储空间连续的数据结构,但是对于存储空间非连续的,就需要寻找一个行为类似指针的类,来对非数组的数据结构进行遍历.因此,我们引入迭代器概念.   一.迭代器(iterator)介绍 ...

  3. C++之STL迭代器(iterator)

    [摘要]本文是对STL--迭代器(iterator)的讲解,对学习C++编程技术有所帮助,与大家分享. 原文:http://www.cnblogs.com/qunews/p/3761405.html ...

  4. 【C++ STL应用与实现】18: 怎样使用迭代器适配器

    本系列文章的文件夹在这里:文件夹. 通过文件夹里能够对STL整体有个大概了解 前言 本文介绍了STL中的迭代器适配器(iterator adapter)的概念及其用法演示样例.迭代器适配器能够和标准库 ...

  5. STL之迭代器(iterator)

    STL的中心思想在于:将数据容器和算法分开,彼此独立设计,最后再用一帖粘着剂将它们撮合在一起.没错,这个粘着剂正是迭代器(iterator).迭代器的主要目的是通过遍历来对容器中元素进行相关操作.算法 ...

  6. function adapter(函数适配器)和迭代器适配器

    所谓function adapter(函数适配器)是指能够将不同的函数对象(或是和某值或某寻常函数)结合起来的东西,它自身也是个函数对象. 迭代器适配器  运用STL中的迭代器适配器,可以使得算法能够 ...

  7. STL源码剖析 迭代器(iterator)概念与编程技法(三)

    1 STL迭代器原理 1.1  迭代器(iterator)是一中检查容器内元素并遍历元素的数据类型,STL设计的精髓在于,把容器(Containers)和算法(Algorithms)分开,而迭代器(i ...

  8. 【C++】:STL迭代器使用---[容器::iterator iter;]

    参考文章:http://blog.csdn.net/qq_23100787/article/details/51388163 迭代器这种东西,就是为了使访问简单!! 容器::iterator iter ...

  9. STL标准库-迭代器适配器

    技术在于交流.沟通,本文为博主原创文章转载请注明出处并保持作品的完整性 这次主要介绍一下迭代器适配器.以reverse_iterator(反向迭代器),insert_iterator(插入迭代器),o ...

随机推荐

  1. PAT Advanced 1006 Sign In and Sign Out (25 分)

    At the beginning of every day, the first person who signs in the computer room will unlock the door, ...

  2. Python小技巧:使用*解包和itertools.product()求笛卡尔积(转)

    leetcode上做提示时候看到有高人用这个方法解题 [问题] 目前有一字符串s = "['a', 'b'],['c', 'd']",想把它分开成为两个列表: list1 = [' ...

  3. 牛客练习赛14 B 区间的连续段 (倍增)

    链接:https://ac.nowcoder.com/acm/contest/82/B来源:牛客网 区间的连续段 时间限制:C/C++ 7秒,其他语言14秒 空间限制:C/C++ 262144K,其他 ...

  4. Codeforces 957 水位标记思维题

    A #include <bits/stdc++.h> #define PI acos(-1.0) #define mem(a,b) memset((a),b,sizeof(a)) #def ...

  5. python set 集合操作

    转自:https://www.cnblogs.com/alex3714/articles/5740985.html s = set([3,5,9,10]) #创建一个数值集合 t = set(&quo ...

  6. python 小游戏,和电脑玩剪刀石头布

    # -*- coding: utf-8 -*- """ Created on Fri Oct 25 16:28:12 2019 if判断综合演练,剪刀石头布 @autho ...

  7. DUBBO原理、应用与面经总结

    研读dubbo源码已经有一段时间了,dubbo中有非常多优秀的设计模式和示例代码值得学习,但是dubbo的调用层级和方法链都较为繁杂,如果不对源码思路进行梳理则很容易忘却,因此总结一篇研读心得,从阅读 ...

  8. 【leetcode】827. Making A Large Island

    题目如下: 解题思路:这个题目可以进行拆分成几个子问题.第一,求出island的数量,其实就是 200. Number of Islands,这个很简单,DFS或者BFS都能搞定:第二,除了求出isl ...

  9. [USACO2019JAN]Sleepy Cow Sorting题解

    拿到这个问题,我们从头开始思考. 我们把序列看做两部分,一部分在前表示待排序的,记为序列1,一部分在后表示已排序的,记为序列2. 因为序列2在后,所以不必担心它影响序列1的排序,那么对于序列1的第一个 ...

  10. warp(图像仿射变换)

    仿射变换是一种二维坐标(x,y)到二维坐标(u,v)的线性变换. 对应的齐次坐标矩阵表示形式为: 仿射变换特点: 直线经仿射变换后依然为直线: ’直线之间的相对位置关系保持不变,平行线经仿射变换后依然 ...