文章目录

  • 前言
  • 插入迭代器
    • inserter
    • front_inserter
    • back_inserter
  • iostream迭代器
    • istream_iterator 读取输入流
      • istream_iterator允许使用懒惰求值
    • ostream_iterator操作
  • 反向迭代器
    • reverse_iterator的base成员函数

前言

除了为每个容器定义的迭代器之外,标准库在头文件iterator中还定义了额外几种迭代器。这些迭代器包括以下几种。

  • 插入迭代器(insert iterator):这些迭代器被绑定到一个容器上,可用来向容器插入元素。
  • 流迭代器(stream iterator):这些迭代器被绑定到输入或输出流上,可用来遍历所关联的IO流。
  • 反向迭代器(reverse iterator):这些迭代器向后而不是向前移动。除了forward_list之外的标准库容器都有反向迭代器。
  • 移动迭代器(move iterator):这些专用的迭代器不是拷贝其中的元素,而是移动它们。


插入迭代器


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

  • back_inserter创建一个使用push_back的迭代器。
  • front_inserter创建一个使用push_front的迭代器。
  • inserter创建一个使用insert的迭代器。此函数接受第二个参数,这个参数必须是一个指向给定容器的迭代器。元素将被插入到给定迭代器所表示的元素之前。

inserter

当调用inserter(c,iter)时,我们得到一个迭代器,接下来使用它时,会将元素插入到iter原来所指向的元素之前的位置。即,如果it是由inserter生成的迭代器,则下面这样的赋值语句:

*it = val;

等价于:

it = c.insert(it, val); // it指向新加入的元素val
++it; // 递增it使其指向原来的元素

front_inserter

一直向首元素位置添加元素,添加后指向新的首元素。

以以下实例区分inserter和front_inserter的区别:


back_inserter

向容器尾部不断添加元素。

以unique_copy函数为实例来观察back_inserter的作用:

值得注意的是,与unique一样,unique_copy也要求在源容器中重复元素是相邻存放的,因此容器如果无序且重复元素未相邻存放,unique_copy会失败,稳妥起见应该先对vector排序。

  vector<int> vi = {2, 6, 7, 13, 15, 20, 22, 23, 25, 30};list<int> li;ostream& os(cout);int n = 10;while(n--){vi.push_back(n);}sort(vi.begin(), vi.end());for(auto i : vi){os << i << ends;}os << endl;unique_copy(vi.begin(), vi.end(), back_inserter(li));for(auto i : li){os << i << ends;}os << endl;

输出结果:



iostream迭代器

虽然iostream类型不是容器,但是标准库定义了可以用于这些IO类型对象的迭代器。


istream_iterator 读取输入流


流迭代器不支持递减运算,因为不可能在一个流中反向移动。

istream_iterator使用>>来读取流。因此,istream_iterator要读取的类型必须定义了输入运算符。

  • 当创建一个istream_iterator时,可以将它绑定到一个流
  • 默认初始化相当于创建一个可以当作尾后值使用的迭代器。


用istream_iterator从标准输入读取数据,存入一个vector:

istream_iterator可以用来构建容器:

istream_iterator<int> in_iter(cin);
istream_iterator<int> eof;
vector<int> vec(in_iter, eof);

本例中我们用一对表示元素范围的迭代器来构造vec。这两个迭代器是istream_iterator,这意味着元素范围是通过从关联的流中读取数据获得的。这个构造函数从cin中读取数据,直至遇到文件尾或者遇到一个不是int的数据为止。从流中读取的数据被用来构造vec。


istream_iterator允许使用懒惰求值

当我们将一个istream_iterator绑定到一个流时,标准库并不保证迭代器立即从流读取数据。 具体实现时可以推迟从流中读取数据的时机——直到我们使用迭代器时才真正读取。标准库中的实现所保证的是,在我们第一次解引用迭代器之前,从流中读取数据的操作已经完成了。 对于大多数程序来说,立即读取还是推迟读取没什么差别。但是,如果我们创建了一个istream_iterator,没有使用就销毁了,或者我们正在从两个不同的对象同步读取同一个流,那么何时读取可能就很重要了。



ostream_iterator操作

可以对任何具有输出运算符(<<运算符)的类型定义ostream_iterator。

当创建一个ostream_iterator时,我们可以提供(可选的)第二参数,它是一个字符串,在输出每个元素后都会打印此字符串。此字符串必须是一个C风格字符串(即,一个字符串字面常量或者一个指向以空字符结尾的字符数组的指针)。

与iostream_iterator不同的是:必须将ostream_iterator绑定到一个指定的流,不允许空的或表示尾后位置的ostream_iterator。

可以用ostream_iterator来输出值的序列:

此程序将vec中的每个元素写到cout,每个元素后加一个空格。每次向out_iter赋值时,写操作就会被提交。

值得注意的是,当我们向out_iter赋值时,可以忽略解引用和递增运算。即,循环可以重写成下面的样子:

istream_iterator<int> in_iter(cin);
istream_iterator<int> eof;
vector<int> vec(in_iter, eof);
ostream_iterator<int> out_iter(cout, " ");
for(auto i : vec){out_iter = i;
}
cout << endl;

运算符*和++实际上对ostream_iterator对象不做任何事情,因此忽略它们对我们的程序没有任何影响。 但是,推荐第一种形式。在这种写法中,流迭代器的使用与其他迭代器的使用保持一致。如果想将此循环改为操作其他迭代器类型,修改起来非常容易。而且,对于读者来说,此循环的行为也更为清晰。

可以通过调用copy来打印vec中的元素,这比编写循环更为简单:

copy(vec.begin(), vec.end(), out_iter);
cout << endl;

可以用unique_copy代替copy只打印不重复元素:



反向迭代器

反向迭代器就是在容器中从尾元素向首元素反向移动的迭代器。对于反向迭代器,递增(以及递减)操作的含义会颠倒过来。递增一个反向迭代器(++it)会移动到前一个元素;递减一个迭代器(- -it)会移动到下一个元素。


反向迭代器逆序打印vector<int>中的元素:

对照普通迭代器可以看出,rbegin指向尾元素,rend指向首元素前,递增和递减操作的含义会颠倒过来:反向迭代器的递增操作会移动到前一个元素。

反向迭代器也有十分方便的时候,比如不加额外参数就可以使得元素降序排列:

reverse_iterator的base成员函数

base成员函数用来将反向迭代器转换成其对应的普通迭代器(当然反过来也是可以的,普通迭代器转换成对应的反向迭代器):

图中的对象显示了普通迭代器与反向迭代器之间的关系。例如,rcomma和rcomma.base()指向不同的元素,line.crbegin和line.cend()也是如此。这些不同保证了元素范围无论是正向处理还是反向处理都是相同的。

从技术上讲,普通迭代器与反向迭代器的关系反映了左闭合区间的特性。关键点在于[line.crbegin(),rcomma)[rcomma.base(),line.cend())指向line中相同的元素范围。为了实现这一点,rcomma和rcomma.base()必须生成相邻位置而不是相同位置,crbegin()和cend()也是如此。


插入迭代器、流迭代器、反向迭代器、移动迭代器相关推荐

  1. C++(标准库):26---STL迭代器之(迭代器的5大种类(输出迭代器、输入迭代器、向前迭代器、双向迭代器、随机访问迭代器))

    一.迭代器的头文件 所有的容器都定义有自己的iterator类型,因此如果单单使用容器,只需要包含对应容器的头文件即可 不过有些特殊的iterator,被定义在头文件<iterator>中 ...

  2. mysql迭代器_迭代器是什么,C++ STL迭代器(iterator)用法详解

    无论是序列容器还是关联容器,最常做的操作无疑是遍历容器中存储的元素,而实现此操作,多数情况会选用"迭代器(iterator)"来实现.那么,迭代器到底是什么呢? 我们知道,尽管不同 ...

  3. python迭代器好处_关于Python中迭代器的作用

    迭代器的定义:含有__iter__()方法和__next__()方法的就是迭代器,即(iterate) 含有__iter__()方法就可以使用for循环,即iterable(可迭代的) Iterabl ...

  4. python生成器与迭代器的区别_python生成器和迭代器的区别

    匿名用户 1级 2016-10-13 回答 迭代器和生成器都是Python中特有的概念,迭代器可以看作是一个特殊的对象,每次调用该对象时会返回自身的下一个元素,从实现上来看,一个可迭代的对象必须是定义 ...

  5. python手写一个迭代器_搞清楚 Python 的迭代器、可迭代对象、生成器

    很多伙伴对 Python 的迭代器.可迭代对象.生成器这几个概念有点搞不清楚,我来说说我的理解,希望对需要的朋友有所帮助. 1 迭代器协议 迭代器协议是核心,搞懂了这个,上面的几个概念也就很好理解了. ...

  6. 迭代器的定义与自定义一个迭代器

    迭代器 1,如何让一个对象成为一个可以迭代的对象? 该对象的内部需要实现 __iter__方法 代码示例: from collections import Iterable, Iterator cla ...

  7. python迭代器和生成器的作用_python迭代器与生成器的详细介绍

    一.什么玩意是迭代器? 先说说什么是迭代吧,迭代就是一件事情重复很多次,比如说for循环. for循环可以对一切有iter方法的对象进行迭代,那么什么是iter方法呢? 一个对象是否可迭代,全都取决于 ...

  8. python迭代器两个基本方法_python迭代器如何实现

    迭代是Python最强大的功能之一,是访问集合元素的一种方式.迭代器是一个可以记住遍历的位置的对象.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退. 迭代器有 ...

  9. java迭代器和for循环区别_迭代器和增强for循环

    Iterator迭代器的使用: 迭代:Iterator,即collection集合元素的通用获取方式 java.util.Iterator接口.迭代器(对集合进行遍历) 有两个常用的方法 Boolea ...

  10. -1-3 java集合框架基础 java集合体系结构 Collection 常用java集合框架 如何选择集合 迭代器 泛型 通配符概念 Properties 集合 迭代器...

    集合又称之为容器存储对象的一种方式 •数组虽然也可以存储对象,但长度是固定的:显然需要可变长度的容器 集合和数组的区别?                 A:长度区别                  ...

最新文章

  1. JavaScript 写几个简单的知识点
  2. Android开发--多媒体应用开发(二)--SoundPool的使用
  3. 软工Hello World!团队第二周博客汇总
  4. javaBean和jsp应用
  5. python搭建网页_使用python快速搭建本地网站
  6. C++ 中的友元(friend)
  7. 运营前线2:一线运营专家的运营方法、技巧与实践03 3步策略做好内容管理
  8. apache 配置虚拟域名默认站点问题
  9. mysql是用啥语言写的_mysql源码是什么语言
  10. 超详细的AI深度学习“花书”笔记(附中英文电子书资料)
  11. 记一次产品需求:图片等比缩放和CSS自适应布局16:9
  12. “踢爆”职场焦虑、玩机车、文科转大厂程序媛,乘风破浪的 IT 女神太飒了!
  13. 怎样实现iMessage群发
  14. 爬虫基本概念(新手必看)
  15. 腾讯云存储产品全线升级,满足更多高性能存储场景
  16. 使用Phaser开发你的第一个H5游戏(一)
  17. Maven连接MySQL数据库
  18. 高精度加法 高精度减法 高度除法 高精度乘法 方法总结
  19. 辰颐物语系统(开发、奖励规则)
  20. GitHub 标星 167k!你要的优质书籍这都有,还开源!

热门文章

  1. sqlite3_finalize sqlite3_close
  2. ISDN与PSTN的区别是什么?
  3. DOC学习之TrueFFS
  4. 软件oem要注意什么_做化妆品oem,选择化妆品包材要注意什么问题
  5. jwt获取token_JWT实现token认证
  6. 初学者怎样看懂python代码_入门编程(初学者怎样看懂代码)
  7. arcgis创建剖面线execl文件
  8. 【转】你不能访问此共享文件夹,因为你组织的安全策略阻止未经身份验证的来宾访问
  9. 第十五节: EF的CodeFirst模式通过DataAnnotations修改默认协定
  10. 第十五节:Expression表达式目录树(与委托的区别、自行拼接、总结几类实例间的拷贝)