定义在头文件iterator。

通用迭代器

所有容器都支持的迭代器操作

  1. //v为标准容器,如vector<int>
  2. v::iterator // 迭代器的类型
  3. v::iterator // 迭代器的类型
  4. v::const_iterator // 常量迭代器类型,由元素是否const动态决定
  5. //v为标准容器,如vector
  6. v.begin() // 指向第一个元素迭代器,或者尾后迭代器(空)
  7. v.end() // 尾后迭代器,只是标记没有了,不指向任何元素
  8. v.cbegin(),v.cend() // 返回常量迭代器,不能进行修改操作。
  9. v.begin() == v.end() // 标准容器是否为空
  10. *iter // 返回迭代器iter所指元素的“引用”
  11. (*iter) = 1 // 所以,赋值操作会直接修改元素值
  12. iter->mem // 等价于(*iter).mem
  13. (*iter).mem // 同上,等价
  14. ++iter // 下一个元素
  15. --iter // 上一个元素
  16. iterl == iter2 // 判断个迭代器指示的是否同一个元 或者 尾后迭代器
  17. iterl != iter2
  18. vector<int> v{10, 20, 30, 40}
  19. for(auto it = v.begin(); it != v.end(); v++); //标准迭代模式,用 != 判断结束
  20. cout << (*it) << endl;
  21. for(auto it = v.begin(); it < v.end(); v++); //错误:以 < 判断结束
  22. v.push_back(1); //严禁!在迭代过程中插入删除元素。

插入迭代器

insert iterator,这些迭代器被绑定到一个容器上,可用来向容器插入元素。重载了迭代器的=赋值运算符,在赋值时插入。有三种类型:

  • back_inserter:
    • 创建一个使用c.push_back(t)插入的迭代器。
  • front_inserter:
    • 创建一个使用c.push_front(t)插入的迭代器。
  • inserter:
    • 创建一个使用c.insert(p, t)插入的迭代器。 ```cpp it = t; //在it指定的当前位置插入值t。假定c是it绑定的容器,依赖于it的不同种类, //此赋值会分别调用: // c.push_back(t) // c.push_front(t) // c.insert(p, t) //其中p为传递给inserter的迭代器位置

*it, ++it , it++; //不会做任何事情。返回it

/**插入迭代器的工作原理**/ iterator it = inserter(c, iter) *it = val; //等价于 it = c.insert(it,val); //it指向新加入的元素 ++it; //递增 it 使它指向原来的元素

/**插入迭代器的使用**/ list lst = {1, 2, 3, 4); list lst2, lst3;

//拷贝完成之后,lst2包含 4 3 2 1 copy(lst.cbegin(), lst.cend(), front_inserter(lst2));

//拷贝完成之后,lst3包含 1 2 3 4 copy(lst.cbegin(), lst.cend(), inserter(lst3, lst3.begin()))

  1. <a name="QURkB"></a>
  2. # 流迭代器
  3. stream iterator,迭代器被绑定到I/O流上,可用来遍历所关联的 IO流。这些迭代器把流看成元素序列。
  4. <a name="Wknf2"></a>
  5. ## istream _iterator
  6. 在it++的时候,触发元素类型的>>运算符从流中读取数据。
  7. <a name="2DMig"></a>
  8. ### 懒惰求值
  9. 标准库并不保证迭代器立即从流读取数据。具体实现可以推迟从流中读取数据,直到我们使用迭代器时才真正读取。准库中的实现所保证的是,在我们第一次解引用迭代器之前,从流中读取数据的操作已经完成了。对千大多数程序来说,立即读取还是推迟读取没什么差别。但是,如果我们创建了 一个 istream_iterator, 没有使用就销毁了,或者我们正在从两个不同的对象同步读取同 一个流,那么何时读取可能就很重要了 。
  10. <a name="bDuVS"></a>
  11. ### 操作
  12. ```cpp
  13. istream_iterator<T> in(is); //in从输入流is读取类型为T的值
  14. istream_iterator<T> end; //读取类型为T的值的istream_iterator迭代器,表示尾后位置
  15. in1 = in2; //in1和in2必须读取相同类型。如果它们都是尾后迭代器,或绑定到相同的输入,
  16. in1 != in2; //则两者相等,否则不相等。
  17. *in; //返回从流中读取的值
  18. in->mem; //与 (*in).mem 的含义相同
  19. ++in , in++; //使用元素的>>运算符从输入流中读取下一个值。与以往一样,
  20. //前置版本返回一个指向递增后迭代器的引用,后置版本返回旧值

例子

  1. istream_iterator<int> int_it(cin); //从cin读取int
  2. istream_iterator<int> int_eof; //默认构造迭代器,构造一个尾后迭代器。
  3. ifstream in("afile");
  4. istream_iterator<string> str_it(in); //从“afile”读取字符串
  5. //*********************************************
  6. istream_iterator<int> in_iter(cin); //从cin读取int
  7. istream_iterator<int> eof; //istream尾后迭代器
  8. while(in_iter != eof) //IO失败,迭代器就等于eof
  9. //后置递增运算读取流,返回迭代器的旧值
  10. //解引用迭代器,获得从流读取的前一个值
  11. vec.push_back(*in_iter++);
  12. //*********************************************
  13. istream_iterator<int> in_iter(cin), eof; //从 cin 读取 int
  14. vector<int> vec(in_iter, eof); //从迭代器范围构造 vec
  15. //从流中读取数据构造vec
  16. //*********************************************
  17. //此调用会计算出从标准输入读取的值的和。如果输入为 :
  18. //23 109 45 89 6 34 12 90 34 23 56 23 8 89 23
  19. //则输出为 664 。
  20. istream_iterator<int> in(cin), eof;
  21. cout << accumulate(in, eof, 0) << endl;

ostream_iterator

iter = val时,触发元素类型的<<运算符,将val写到输出流。
写迭代器不需要移动。

操作

  1. ostream_iterator<T> out(os); //out将类型为T的值写到输出流os中
  2. ostream_iterator<T> out(os, d); //out将类型为T的值写到输出流os,
  3. //同时每个值后面都输出一个d。
  4. //d指向一个空字符结尾的字符数组
  5. ostream_iterator<T> out; //错误:不能为空/或者尾后迭代器。
  6. out = val; //用<<运算符将val写入到out所绑定的ostream中。
  7. //val的类型必须与 out 可写的类型兼容
  8. //这些运算符是存在的,但不对out做任何事情。每个运算符都返回out
  9. *out, ++out, out++;

例子

  1. ostream_iterator<int> out_iter(cout," ");
  2. for (auto e : vec)
  3. *outiter++ = e; //想等于cout << *outiter << " ",这个空格就是上面的第二个参数
  4. out_iter = e; //同上等价但不推荐,实际上*和++运算符对迭代对象不做任何事情
  5. cout << endl;
  6. //效果同上。
  7. copy(vec.begin(), vec.end(), out_iter);
  8. cout << endl ;
  1. istream_iterator<Sales_item> item_iter (cin), eof;
  2. ostream_iterator<Sales_item> out_iter(cout, " \n " ) ;
  3. Sales_item sum = *item_iter++; //将第一笔交易记录存在sum中,并读取下一条记录
  4. while (item_iter != eof) {
  5. //如果当前交易记录(存在item_iter中有着相同的 ISBN 号
  6. if (item_iter->isbn() == sum.isbn())
  7. sum += *item_iter++; //将其加到 sum 上并读取下一条记录
  8. else{
  9. out_iter = sum; //输出sum当前值
  10. sum = *item_iter++; //继续读取下一条记录
  11. }
  12. }
  13. out_iter = sum; //记得打印最后一组记录的和

反向迭代器

reverse iterator,iter++与iter—的行为颠倒, 除了forward_list都有反向迭代器。
通过以下方式获得:

  • c.rbegin(),c.crbegin()
  • c.rend(),c,crend()

当我们从一个普通迭代器初始化一个反向迭代器或是给一个反向迭代器赋值时,结果迭代器与原迭代器指向的并不是相同的元素。左闭右开区间的问题
image.png
下图是vector容器的四种迭代器含义。
image.png

  1. //逆序打印vector容器。
  2. vector<int> vec = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
  3. //从尾元素到首元素的反向迭代器
  4. for(auto r_iter = vec.crbegin(); //将 r_iter 绑定到尾元素
  5. r_iter != vec.crend(); // crend 指向首元素之前的位置
  6. ++r_iter) //实 际是递减 , 移动到前 一 个元素
  7. cout << *r_iter << endl ; //打印 9 , 8 , 7 , . .. 0
  8. //正序排序、逆序排序
  9. sort(vec.begin(), vec.end()); //按“正常序”排序vec
  10. sort(vec.rbegin(), vec.rend()); //按逆序排序:将最小元素放在vec的末尾
  11. //输出第一个单词
  12. string line("FIRST,MIDDLE,LAST");
  13. auto comma = find(line.cbegin(), line.cend(), ',');
  14. cout << string(line.cbegin(), comma) << endl; //LAST
  15. //输出最后一个单词
  16. string line("FIRST,MIDDLE,LAST");
  17. auto rcomma = find(line.crbegin(), line.crend(), ',');
  18. cout << string(line.crbegin(), rcomma) << endl; //TSAL,这单词都颠倒了怎么搞的。
  19. //rcomma.base()得到一个正向迭代器。
  20. cout << string(rcomma.base(), line.cend()) << endl; //这样才能正常

移动迭代器

move iterator,这些专用的迭代器不是拷贝其中的元素,而是移动它们。