本文来源:《C++语言程序设计》第10章
理解迭代器对于理解STL框架并掌握STL的使用至关重要。
迭代器是泛化的指针,STL算法利用迭代器对存储在容器中的元素序列进行遍历,迭代器提供了访问容器中每个元素的方法。
虽然指针也是一种迭代器,但迭代器不仅仅是指针。
指针可以指向内存中的一个地址,通过这个地址就可以访问相应的内存单元。
迭代器更为抽象,它可以指向容器中的一个位置,我们不必关心这个位置对应的真正物理位置,只需要通过迭代器访问这个位置的元素。
------
在STL中迭代器是算法和容器的中间人。
遍历链表需要使用指针
对数组元素进行排序时也需要通过指针访问数组元素(数组名本身就是一个指针)
指针便充当了算法和数据结构的中间人。
在STL中,容器是封装起来的类模板,其内部结构无从知晓,而只能通过容器接口来使用容器。
但STL中的算法是通用的函数模板,并不专门针对某一个容器类型。
算法要适用于多种容器,而每一种容器中有效的元素又可以是任何类型,如何使用普通的指针来充当中介呢?
这时就必须使用更为抽象的指针,也就是迭代器。
就像声明指针时要说明其指向的元素一样,STL的每一个容器类模板中,都定义了一组对应的迭代器类。
使用迭代器,算法函数可以访问容器中指定位置的元素,而无需关心元素的具体类型。
------
输入流迭代器
cin是输入流的一个实例
输入流迭代器用来从一个输入流中连续地输入某种类型的数据,它是一个类模板。
template<class T>istream_iterator<T>;
由于STL设计得非常灵活,很多STL的模板都有三四个模板参数,但排在后面的参数一般都有默认的参数值,绝大部分程序中都会忽略这些参数而使用它们的默认值。
istream_iterator实例上有多大4个模板参数。这里仅给出一个没有默认值的模板参数,便于理解。
其中,T是使用该迭代器从输入流中输入数据的类型。
类型T要满足两个条件:
(1)有默认构造函数
(2)对该类型的数据可以使用">>"从输入流输入。
一个输入流的实例需要由下面的构造函数来构造:
istream_iterator(istream& in);
在该构造函数中,需要提供用来输入数据的输入流(例如cin)作为参数。一个输入流迭代器实例支持"*",“->”,"++"等几种运算符。
用"*"可以访问刚刚读取的元素;
用"++"可以从输入流中读取下一个元素;
若类型T是类类型或结构类型,用“->”可以直接访问刚刚读取元素的成员。
如何判断一个输入流是否已经结束呢?
istream_iterator类模板有一个默认构造函数
istream_iterator();
用该函数构造出的迭代器指向的就是输入流的结束位置,将一个输入流与这个迭代器进行比较就可以判断输入流是否结束。
#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
int main() {
std::istream_iterator<int> eos; // 输入流结束迭代器
std::istream_iterator<int> i(std::cin); // 绑定到 std::cin 的迭代器
// 使用 std::copy 算法从 std::cin 复制整数到 vector
std::vector<int> vec;
std::copy(i, eos, std::back_inserter(vec));
// 输出 vector 中的元素
std::copy(vec.begin(), vec.end(), std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
return 0;
}
由于该程序会从标准输入流中读取数据直到输入流结束,运行该程序时,输入完数据后,在Windows下需要按Ctrl+Z和回车键,表示标准输入结束。