虽然iostream类型不是容器,但标准库定义了可以用于这些IO类型对象的迭代器。istream_iterator读取输入流,ostream_iterator向一个输入流写数据。这些迭代器将它们对应的流当做一个特定类型的元素序列来处理。通过使用流迭代器,我们可以用泛型算法从流对象读取数据以及向其写入数据。
istream_iterator操作
当创建一个流迭代器时,必须指定迭代器将要读写的对象类型。一个istream_iterator使用>>来读取流。因此,istream_iterator要读取的类型必须定义了输入运算符。当创建一个istream_iterator时,我们可以将它绑定到一个流。当然,我们还可以默认初始化迭代器,这样就创建了一个可以当作尾后使用的迭代器。
istream_iteratorint_it(cin); //从cin读取int
istream_iteratorint_eof; //尾后迭代器
ifstream in("afile");
istream_iteratorstr_it(in); //从"afile"读取字符串
下面是一个用istream_iterator从标准输入读取数据,存入一个vector的例子:
istream_iterator in_iter(cin); //从cin读取int
istream_iterator eof; //istream尾后迭代器
while(in_iter!=eof) //当有数据可供读取时
//后置递增运算符读取流,返回迭代器的旧值
//解引用迭代器,获得从流读取的前一个值
vec.push_back(*in_iter++);
此循环从cin读取int值,保存在vec中。在每个循环步中,循环体代码检查in_iter是否等于eof。eof被定义为空的istream_iterator,从而可以当作尾后迭代器来使用。对于一个绑定到流的迭代器。一旦其关联的流遇到文件尾或遇到IO错误,迭代器的值就与尾后迭代器相等。
下面一个例子体现了istream_iterator更有用的地方:
istream_iterator in_iter(cin),eof; //从cin读取int
vectorvec(in_iter,eof); //从迭代器范围构造vec
本例中我们一对表示元素范围的迭代器来构造vec。这两个迭代器是istream_iterator,这意味着元素范围是通过从关联的流中读取数据获得的。这个构造函数从cin中读取数据,直至遇到文件尾或者遇到一个不是int的数据为止。从流中读取的数据被用来构造vec。
使用算法操作流迭代器
由于算法使用迭代器操作来处理数据,而迭代器又至少支持某些迭代器操作,因此,我们至少可以用某些算法来操作流迭代器。下面是一个例子,用一对istream_iterator来调用accumulate:
istream_iterator in(cin),eof;
cout<
此调用会计算出标准输入读取的值的和。如果输入为:
23 109 45 89 6 34 12 90 34 23 56 23 8 89 23
则输出为664。
istream_iterator允许使用懒惰求值
当我们将一个istream_iterator绑定到一个流时,标准库并不保证迭代器立即从流读取数据。具体实现可以推迟从流中读取数据,直到我们使用迭代器才真正读取。标准库中的实现所保证的是,在我们第一次解引用迭代器之前,从流中读取数据的操作已经完成了。对于大多数程序来说,立即读取还是推迟读取没什么差别。但是,如果我们创建了一个istream_iterator,没有使用就销毁了,或者我们正从两个不同的对象同步读取一个流,那么何时读取可能就很重要了。
ostream_iterator操作
我们可以对任何具有输出运算符(<<运算符)的类型定义ostream_iterator。当创建一个ostream_iterator时,我们可以提供(可选的)第二参数,它是一个字符串,在输出每个元素后都会打印此字符串。此字符串必须是一个C风格字符串(即,一个字符串字面值常量或者一个指向以空字符结尾的字符数组指针)。必须将ostream_iterator绑定到一个指定的流,不允许空的或表示尾后位置的ostream_iterator。
下面是ostream_iterator的操作:
ostream_iterator out(os); //out将类型为T的值写到输出流os中
ostream_iterator out(os,d); //out将类型为T的值写到输出流os中,每个值后面都输出一个d。
out = val //用<<运算符将val写入到out所绑定的ostream中。val的类型必须与out可写的类型兼容
*out,++out,out++ //这些运算符是存在的,但不对out做任何事情。每个运算符都返回out
我们可以用ostream_iterator来输出值的序列:
ostream_iterator out_iter(cout," ");
for(auto e : vec)
*out_iter++=e; //赋值语句实际上将元素写到cout
cout<
此程序将vec中的每个元素写到cout,每个元素后加一个空格。每次向out_iter赋值时,写操作就会被提交。
值得注意的是,当我们向out_iter赋值时,可以忽略解引用和递增运算。即,循环可以重写成下面的样子:
for(auto e : vec)
out_iter=e; //赋值语句将元素写到cout
cout<
运算符*和++实际上对ostream_iterator对象不做任何事情,因此忽略它们对我们的程序没有任何影响。但是,推荐第一种形式。在这种写法中,流迭代器的使用与其他迭代器的使用保持一致。如果想将此循环改为操作其他迭代器类型,修改起来非常容易。而且,对于读者来说,此循环的行为更为清晰。
可以通过copy来打印vec中的元素,这样编写循环更为简单:
copy(vec.begin(),vec.end(),out_iter);
cout<
使用流迭代器处理类类型
我们可以为任何定义了输入运算符(>>)的类型创建istream_iterator对象。类似的,只要类型有输出运算符(<<),我们就可以为其定义ostream_iterator。比如一个Counter类,既有输入运算符也有输出运算符,因此可以使用IO迭代器。如下所示
istream_iterator Cou_iter(cin),eof;
ostream_iterator out_iter(cout,"\n");