1、自C++11起可以用range-based for循环来所有元素,但有时并不需要处理所有元素,此时可以使用迭代器。

std::vector<int> vec {1,2,3,4,5,6,7,8,9,10};
for (auto n : vec){std::cout << n << endl;
}

2、迭代器中用来表现容器中的某个位置

  • operator * :返回当前位置上的原始值。如果该元素拥有成员,可用-->取用他它们。
  • operator  ++ :返回当前位置上的元素值,有些迭代器还可以使用operator ——退至前一元素。(注:“前置++”比“后置++”效率高)
  • operator == 和 !=:判断两个迭代器是否指向同一位置。
  • operator = :对迭代器赋值。

3、容器的begin()和end()

begin():返回一个迭代器,指向容器终点,即第一个元素(如果有的话)的位置。

end():返回一个迭代器,指向容器终点。终点位于最末元素的下一位置,又称“逾尾迭代器”。

4、range-based for循环VS迭代器

对容器而言rang-based for循环不过是个便捷接口,用来迭代它“所接收到的几何区间”内每一个元素。在循环体内,真实元素被“当前迭代器所指向的value”初始化。

(1)range-based for循环

for (type  elem : coll){

...

}

(2)迭代器

for(auto pos = coll.begin(), end = coll.end(); pos != end; ++pos+){

type elem = *pos;

...

}

5、迭代器的种类

(1)前向迭代器(Forward iterator) 只能够以累加操作符(increment operator) 向前迭代。

Class forward _list的迭代器就属此类。其他容器如unordered_ set、 unordered_multiset、 unordered_map和unordered_multimap 也都至少是此类别(但标准库其实为它们]提供的是双向迭代器[forward iterator]。

(2)双向迭代器(Bidirectional iterator)顾 名思义它可以双向行进:以递增(increment)运算前进或以递减(decrement) 运算后退。list. set、 multiset、 map 和multimap提供的迭代器都属此类。

(3)随机访问迭代器(Random-access iterator)它 不但具备双向迭代器的所有属性,还具备随机访问能力。更明确地说,它们提供了迭代器算术运算的必要操作符(和寻常指针的算术运算完全对应)。你可以对迭代器增加或减少- - 个偏移量、计算两迭代器间的距离,或使用<和>之类的relational (相对关系)操作符进行比较。vector, deque.array和string提供的迭代器都属此类。除此之外,STL还定义了两个类别:

●输入型迭代器(Input iterator) 向前选代时能够读取/处理value。 Input stream迭代器就是这样-一个例子。

●输出型迭代器(Output iterator) 向前迭代时能够涂写value。 Inserter 和output stream迭代器都属此类。

6、具体迭代器

(1)output迭代器

a、output迭代器允许一步一步前行并搭配writ动作。

可以一个一个元素地赋值,但不能使用output迭代器对同一区间迭代两次。无比较操作,无法检验output迭代器是否有效,或写入是否成功。

b、output迭代器的操作

c、通常,迭代器可用来读,也可用来写,几乎所有reading迭代器都有write 的额外功能,这种情况下它们]被称为mutable (可产生变化的)迭代器。

一个典型的pure output迭代器例子是:“将元素写至标准输出设备(例如屏幕或打印机)”。如果采用两个output迭代器写至屏幕,第二个字将跟在第一个字后面,而不是覆盖(overwrite)第一个字。另一个典型例子是inserter,那是一种用 来将value 插入(insert) 容器内的迭代器:如果你赋值(assign) 一个value,你其实是将它插入(insert) 容器。如果随后写入第二个value,并不会覆盖第一个 value,而是安插进去。

(2)input迭代器

a、input迭代器只能一次一个以前行方向读取元素,按此顺序一个一个返回元素值。

input迭代器只能读取元素。如果复制input迭代器,并令input迭代器和新产生的拷贝都前向读取,可能会有不同的值。

b、input迭代器的操作

c、所有迭代器都具备input迭代器的能力,而且往往更强。Pure input迭代器的典型例子就是“从标准输人设备(往往是键盘)读取数据”。同一个值不会被读取两次。一旦从input stream读人一个字(离开input缓冲区),下次读取时就会返回另一一个字。

(3)forward(前向)迭代器

a、forward迭代器是一种input迭代器且在前进读取时提供额外保证。

b、forward迭代器的操作

(4)bidirectional(双向)迭代器

a、bidirectional迭代器是在 forward迭代器的基础上增加了回头迭代器能力。

b、bidirectional迭代器新增操作

c、bidirectional迭代器由一下对象和类型提供:

  • Class list<>
  • Associative (关联式)容器。

如果bidirectional迭代器履行了output迭代器立有的条件,那么它就是个mutable bidirectional迭代器,既可用于读取,也可用于涂写。

(5)Random-Access(随机访问)迭代器

a、random-access迭代器是在bidirectional迭代器的基础上增加了随机访问的能力。因此它能提供iterator算术运算,即它能增减某个偏移量、计算距离,并运诸如<和>等关系操作符进行比较。

b、random-access迭代器的新增的操作

d、random-access迭代器提供者:

  • 可随机访问的容器(array、vector、deque)
  • String(string、wstrin)
  • 寻常的C-style array(pointer)

注:在使用的时候注意迭代器指向的位置,特别是一些特殊的位置,比如begin()前面,或者end()后面则会产生越界。

7、迭代器相关辅助函数

(1)advance()

a、advance()课件迭代器的位置增加,增加幅度由实参决定,即它令迭代器一次前景(或后退)多个元素。

b、#include<iterator>

void advance (InputIterator& pos, Dist n)

●令名称为pos的 input迭代器前进(或后退) n个元素。

●对bidirectional迭代器和random-access迭代器而言,n可为负值,表示向后退。

●Dist是个 template类型。通常它必须是个整数类型,因为会调用诸如<. ++. -- 等操作,还要和0做比较。

●advance() 并不检查迭代器是否超过序列的end() (因为迭代器通常不知道其所操作的容器,因此无从检查)。所以,调用advance()有可能导致不明确行为--因为 “对序列尾端调用operator++"是一种未被定义的行为。

(2)next()和prev()

a、用于前进和后退移动迭代器的位置

b、next()

#include<iterator>

ForwardIterator next(ForwardIterator pos)

ForwardIterator next(ForwardIterator pos, Dist n)

●导致 forward迭代器pos前进1或n个位置。

●如果 处理的是bidirectional和random-access迭代器,n可为负值,导致后退(回头)移 动。

●Dist是类型std: :iterator _traits<ForwardIterator>: :difference. type。●其内部将对一个临时 对象调用advance (pos,n)。

●注意,next()并不检查是否会跨越序列的end()。 因此调用者必须自行担保其结果有效。

c、prev()

BidirectionalIterator prev(BidirectionalIterator pos)

BidirectionalIterator prev(BidirectionalIterator pos, Dist n)

●导致 bidrctional迭代器pos后退1或n个位置。

●n可为负值,导致向前移动。

●Dist是类型std::iterator. traits<BidirectionalIterator>: :difference_type。

●其内部将对一个临时对象调用advance(pos, -n)。

●注意,prev()并不检查是否会跨越序列的begin()。因此调用者必须自行担保其结果有效。注:next()和prev()始自C++11,因此若以operator++和--取而代之,有可能无法针对每一种容器都通过编译。

(3)distance()

a、distance()用来处理两个迭代器之间的距离

b、#include<iterator>

Dist distance (InputIterator pos1, InputIterator pos2)

●返回两个input迭代器posI和pos2之间的距离。

●两个迭代器必须指向同一个容器。

●如果不是random-access迭代器,则从pos1开始前进必须能够到达pos2, 亦即pos2的位置必须与posl相同或在其后。

●返回类型Dist是迭 代器相应的difference类型:

iterator_ traits<InputIterator>: :difference_ type

(4)iter_swap()

a、iter_swap()这个辅助函数用来交换两个迭代器所指的元素值

b、#include<algorithm>

void iter_swap(ForwardIterator1 pos1, ForwardIterator2 pos2 )

  • 交换迭代器pos1和pos2所指的值
  • 迭代器的类型不必相同,但其所指的两个值必须可以互相赋值

8、迭代器适配器

(1)反向迭代器

反向处理元素

例:

void print(int elem) {cout << elem << ' ';
}int main()
{list<int> coll = { 1, 2, 3, 4, 5 };for_each(coll.begin(), coll.end(), print);cout << endl;for_each(coll.rbegin(), coll.rend(), print);cout << endl;system("pause");return 0;
}

输出:

注:rebegin():逻辑位置是从最后一个位置的后一个位置起算的,但其物理位置为他的前面一位。

rend():指针逻辑位置为第一位,物理位置为第一位的前面一位(有时候并不存在)。

注:foreach()

函数原型:

template<typename InputIterator, typename Function>
Function for_each(InputIterator beg, InputIterator end, Function f) {while(beg != end) f(*beg++);
}

b、迭代器和反向迭代器

反向迭代器的逻辑位置和物理位置的值不一样。

(图1)反向迭代器的位置和其value(其所指元素值)的关系

(图2)迭代器pos和reverse(反向)迭代器rpos直接的转换

注:

reverse 迭代器的设计者运用了一个小技巧:他们实际倒置了“半开原则”。Reverse迭代器听定义的区间,并不包括起点,反倒是包括了终点。然而逻辑上其行为一如往常。这么一来reverse迭代器物理意义所指的元素位置,和逻辑意义所指的元素位置就不一致(如图1所示)。现在问题是,将一个迭代器转化为reverse迭代器,过程中发生了什么?该迭代器所保持(履行)的究竟是逻辑位置(value) 还是物理位置(element)? 从上面的例子可知,后者才是答案。因此,其value (也就是其所指元素值)也就移到了前一个元素身上(如图2所示)。

注:

以图2为例,当我们]把pos转换为rpos,它们指向同-一点,但它们所代表的意义(或说它们所代表的逻辑位置)不同了,*pos 为5,*rpos 则是4。换另一个角度看,如果你把[rbegin(), rend())形成的区间颠倒过来(把图上下颠倒看),你会发现其性质就和以[begin(), end()形成的区间完全- 样。

例:

    vector<int> coll = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };vector<int>::const_iterator pos;for_each(coll.begin(), coll.end(), print);cout << endl;pos = find(coll.begin(), coll.end(), 5);cout << &pos << " pos: " << *pos << endl;vector<int>::const_reverse_iterator rpos(pos);for_each(coll.rbegin(), coll.rend(), print);cout << endl;cout << &rpos << " rpos: " << *rpos << endl;

输出:

注:find():返回第一次找到元素的位置

例:

#include<iostream>
#include<deque>
#include<deque>
#include<algorithm>using namespace std;void print(int elem) {cout << elem << ' ';
}int main()
{deque<int> coll = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };deque<int>::const_iterator pos1;pos1 = find(coll.cbegin(), coll.cend(), 2);deque<int>::const_iterator pos2;pos2 = find(coll.cbegin(), coll.cend(), 7);for_each(pos1, pos2, print);cout << endl;// [pos1, pos2)deque<int>::const_reverse_iterator rpos1(pos1);deque<int>::const_reverse_iterator rpos2(pos2);for_each(pos1, pos2, print);cout << endl;system("pause");return 0;
}

输出:

c、运用base()将reserve迭代器转回正常

base()可以将reserve迭代器转回正常的迭代器

例:

vector<int> coll = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
vector<int>::const_iterator pos;
pos = find(coll.begin(), coll.end(), 5);
cout << "pos: " << *pos << endl;vector<int>::const_reverse_iterator rpos(pos);
cout << "rpos: " << *rpos << endl;vector<int>::const_iterator rrpos;
rrpos = rpos.base();
cout << "rrpos: " << *rrpos << endl;

(2)insert(安插型)迭代器

a、用来将“赋予新值”动作转换为“安插新值”动作。算法将执行安插行为而非覆写行为。

b、insert迭代器允许的操作

  • operator *别实现为一个无作用的no-op,仅仅返回*this。所以对insert迭代器来说,*pos与pos等价。
  • 赋值动作(assignment) 被转化为安插动作(insertion)。 事实上,insert 迭代器会调用容器的push. back()、push. .front()或insert()成员函数。

c、insert迭代器的中类

C++标准库提供三种insert迭代器: back inserter, front inserter和general inserter。它们之间的区别在于安插的位置。事实上,它们各自调用所属容器中不同的成员函数。所以insert迭代器初始化时- -定要清楚指明所属的容器是哪一种。

每一种insert迭代器都可以由一个对应的便捷函数加以生成和初始化。

注:容器本身要支持insert迭代器所调用的函数。back_insert只能用在vector、deque、list和string上,front_insert只能用在deque和list上。

例:back_insert_iterator

#include<iostream>
#include<iterator>
#include<vector>
#include<algorithm>using namespace std;void print(int elem) {cout << elem << ' ';
}int main()
{vector<int> coll;back_insert_iterator<vector<int> > iter(coll);*iter = 1;iter++;*iter = 2;for_each(coll.begin(), coll.end(), print);cout << endl;back_inserter(coll) = 23;back_inserter(coll) = 65;for_each(coll.begin(), coll.end(), print);cout << endl;coll.reserve(2 * coll.size());   //注意在调用copy之前要保证有足够的空间copy(coll.begin(), coll.end(), back_inserter(coll));for_each(coll.begin(), coll.end(), print);cout << endl;system("pause");return 0;
}

输出:

注:general insert(insert_iterator)

根据两个实参完成初始化:容器;待安插的位置

general insert对所以容器适用(除array和forward list)

例:

#include<iostream>
#include<set>
#include<list>
#include<algorithm>
#include<iterator>using namespace std;void print(int elem) {cout << elem << ' ';
}int main()
{set<int> coll;insert_iterator<set<int> > iter(coll, coll.begin());*iter = 1;iter++;*iter = 2;inserter(coll, coll.end()) = 66;inserter(coll, coll.end()) = 88;cout << "set: ";for_each(coll.begin(), coll.end(), print);cout << endl;list<int> coll2;copy(coll.begin(), coll.end(), inserter(coll2, coll2.begin()));cout << "list: ";for_each(coll2.begin(), coll2.end(), print);cout << endl;copy(coll.begin(), coll.end(), inserter(coll2, ++coll2.begin()));cout << "list: ";for_each(coll2.begin(), coll2.end(), print);cout << endl;system("pause");return 0;
}

输出:

(3)Stream(串流)迭代器

1)ofstream

Ostream迭代器可以将“被赋值”(assigned value)写人output stream.用了它,算法就可以直接写人stream.其实现机制与insert迭代器概念一致,唯一的区别在f ostream迭代器将赋值动作转化为output动作(通过operator<<)。 如此一来算法就可以使用寻常的选代器接口直接对stream执行涂写动作。

ostream 迭代器提供的各项操作:

例:

int main()
{ostream_iterator<int> intWriter(cout, "\n");*intWriter = 61;intWriter++;*intWriter = 88;vector<int> coll = { 1, 2, 3, 4, 5, 6 };copy(coll.begin(), coll.end(), ostream_iterator<int>(cout, "<"));cout << endl;return 0;
}

输出:

2)istream

从input stream读取元素,注意可能读取会失败(读取到文件尾部,或读取失败),终点位置可以使用end-of-stream,只要任何一次读取失败,所以istream迭代器都会变成end-of-stream迭代器,所以进行一次读取后,应该将istream迭代器拿来和end-of-stream迭代器做比较,看此迭代器是否还有效。

操作如下:

如果满足一下条件则说明两个istream迭代器相等:

  • 两者都是end-of-stream迭代器(因而不能再进行读取)或
  • 两者都可以再进行读取,并指向相同的stream

例:

int main()
{istream_iterator<int> intReader(cin);istream_iterator<int> intReaderEOF;while (intReader != intReaderEOF){cout << "once:      " << *intReader << endl;cout << "once again:" << *intReader << endl;++ intReader;}return 0;
}

读取到f(类型不匹配)时退出

例:

int main()
{istream_iterator<int> cinPos(cin);ostream_iterator<int> coutPos(cout, "-->");while (cinPos != istream_iterator<int>()){advance(cinPos, 2);     //跳过输入单元if (cinPos != istream_iterator<int>())   //检查istream迭代器是否有效,防止越界{*coutPos++ = *cinPos++;}}cout << endl;return 0;
}

(4)move迭代器

以move迭代器取代copy,将元素从一个区间放到另一个区间。

例:

std::list<std::string> s;std::vector<string> v1(s.begin(), s.end());             // 把字符串s复制到v1std::vector<string> v2(make_move_iterator(s.begin()),        // 把字符串s移动到v2make_move_iterator(s.end()));

一般而言,只有当“算法将元素从某个来源区间迁移(transfer) 至某个目标区间”,这种情况下在算法中使用move迭代器才有意义。此外,你必须确保每个元素只被处理- -次,否则,其内容将被搬移一次以上,那会导致不明确的行为。

注意,唯一保证“元素只被读取或被处理-次”的迭代器种类是input iterator。因此,通常只有当“某算法有个来源端,其内要求input iterator. 并且有个目的端,其内使用output iterator”,这时候使用move迭代器才有意义。唯例外是for. each(),它可处理波指明区间(passed range)内的被搬移元素(moved element),例如把它们搬移到一个新容器内。

C++中STL各个迭代器详解相关推荐

  1. STL 中map的用法详解

    STL 中map的用法详解 Map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力,由于这个特性,它完成有可 ...

  2. Java中Iterator迭代器详解

    目录 一.Java中Iterator迭代器详解 1.为什么需要迭代器 2.迭代器长什么样子 3.如何使用迭代器 使用步骤: 代码演示: 迭代器可以简化为增强型for循环: 4.Iterator与Lis ...

  3. c语言stl模板,c/c++开发分享C++ 标准模板库 STL 顺序容器详解

    c++ 标准模板库 stl 顺序容器 容器 顺序性 重复性 支持迭代器 vector 动态数组 无序 可重复 随机访问迭代器 deque 双向队列 无序 可重复 随机访问迭代器 list 双向链表 无 ...

  4. c++中vector的用法详解

    c++中vector的用法详解 vector(向量): C++中的一种数据结构,确切的说是一个类.它相当于一个动态的数组,当程序员无法知道自己需要的数组的规模多大时,用其来解决问题可以达到最大节约空间 ...

  5. python数据处理常用函数_pytorch中的自定义数据处理详解

    pytorch在数据中采用Dataset的数据保存方式,需要继承data.Dataset类,如果需要自己处理数据的话,需要实现两个基本方法. :.getitem:返回一条数据或者一个样本,obj[in ...

  6. python构造自定义数据包_pytorch中的自定义数据处理详解

    pytorch在数据中采用Dataset的数据保存方式,需要继承data.Dataset类,如果需要自己处理数据的话,需要实现两个基本方法. :.getitem:返回一条数据或者一个样本,obj[in ...

  7. [学习C++ ]C++ STL 全排列函数详解(排列组合与匹配算法)--1

    一.概念 从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列.当m=n时所有的排列情况叫全排列.如果这组数有n个,那么全排列数为n!个. 比如a ...

  8. html5代码转换为视频,HTML5中的视频代码详解

    摘要 腾兴网为您分享:HTML5中的视频代码详解,智学网,云闪付,易推广,小红书等软件知识,以及360win10,流量魔盒,fitbit,上港商城,安卓2.3.7,全民惠,五年级下册英语单词表图片,t ...

  9. VMware虚拟机文件夹中各文件作用详解

    VMware虚拟机文件夹中各文件作用详解 虚拟机的文件管理由VMware Workstation来执行. 一个虚拟机一般以一系列文件的形式储存在宿主机中, 这些文件一般在由workstation为虚拟 ...

最新文章

  1. MySQL 的“root”用户修改密码
  2. C++之编码问题(Unicode,ASCII,本地默认)
  3. 黑马程序员pink老师前端入门教程,零基础必看的JavaScript基础语法视频教程
  4. python3随笔-特征值,特征向量,逆矩阵
  5. Python入门--面向过程,面向对象,类与对象
  6. 华为OLT(MA5680T)查看光模块信息及光衰
  7. java 生成高清缩略图_java生成高清缩略图
  8. 计算机硬盘被配制成动态磁盘。在这种情况下无法进行重装?,动态磁盘转换为基本磁盘(完美解决方案)...
  9. 港中文深圳校区计算机研究生怎么样,港中文(深圳)就业报告:应届生年薪40万!这所学校值得读吗?...
  10. (Matlab)复现《改进NSGA_II算法求解考虑运输约束的柔性作业车间节能调度问题》中的交叉操作
  11. ckplayer在线播放流媒体
  12. c语言码流文件,视频文件大小的计算以及视频在网络上的传输(KB、kb、GB、kbps码率)...
  13. 从大数据+AI 谈谈概念与场景
  14. 判定两颗二叉树是否相同
  15. openCV图片倾斜矫正(java版)
  16. Telnet服务配置
  17. Ubuntu 18.04 如何固定图标到任务栏
  18. 手把手教你使用ModelArts的自动学习识别毒蘑菇分类
  19. 求一个给定的n阶方阵的鞍点
  20. 应届生从头脑风暴到游戏策划案的个人思路(三)(初稿)

热门文章

  1. Android Sdk安装和环境变量配置
  2. AndroidStudio之Robolectric单元测试 No Such manifest file
  3. https - nginx反向代理 - nginx端口映射
  4. python实现九九乘法
  5. MTK Nucleus OS之初识
  6. 大众点评店铺详情页评论采集(破解css文字映射反爬,包含项目github 可用时间至2020-01-21)
  7. OpenCL 通用编程与优化(3)
  8. python基础(字符串)
  9. 第四次工业革命到来 中企动力赋企业“生长之力”
  10. 客户的安全性和透明度才是重要的