使用输入输出流迭代子,最大的好处就是减少键盘敲击次数,这也是迭代子(iterator)本身具有的好处, 当然你还可以说,它使用你的代码更简洁易读什么的。也确实,使用一条语句来实现逐个输出vector里的元素到屏幕上, 比写一个for循环要简洁且容易理解多了。
在聊输入输出流迭代子之前,还是说明一下,我针对的代码来自g++4.4,具体说是<bits/stream_iterator.h>
,我的工作平台是Ubuntu, 自然使用g++来开发C++啦。使用微软的VC开发的朋友,虽然面对的环境不一样,不过,我想标准C++库的实现原理应该是基本一致的。
<stream_iterator.h>
里定义了class istream_iterator
和class ostream_iterator
,分别为输入流迭代子和输出流迭代子, 前者方便你完成输入工作,后者帮你完成输出工作,由于他俩是迭代子,所以自然是从class iterator
继承而来。
我们先来看看输出流迭代子,相比而言,它会更有用一些,至少我现在是这么认为的。输出流迭代子有两个成员变量: _M_stream输出流指针,一般指向cout,以作为标准输出流的迭代子,_M_string分界字符串,就是在完成输出工作后, 再自动输出该字符串,如果设置为“,”,那么你的输出内容后面会自动带上一个逗号“,”。 该类最重要的成员函数为operator=()
:
ostream_iterator& operator=(const _Tp& __value)
{
*_M_stream << __value;
if (_M_string) *_M_stream << _M_string;
return *this;
}
这就一目了然了,所以只要你对该迭代子进行赋值,实际上是调用cout<<
进行输出,输出完后,如果_M_string不为空, 也把它输出。还有一些其他的重载操作符,不过用处不大,具体可以自行查看stream_iterator.h
源码。
有了这个方法带给我们最大的好处就是可以与算法中的copy()或者unique_copy()结合, 能够一句话输出容器中的所有元素,例子代码如下:
#include <iterator>
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
int main()
{
ostream_iterator<int> oit(cout,"<=>");
oit = 100;
oit = 99;
return 0;
}
运行结果为:
100<=>99<=>
#include <iterator>
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
int main()
{
int a[] = {1,2,3,4,5};
vector<int> v(a,a+5);
copy(v.begin(),v.end(),ostream_iterator<int>(cout,", "));
return 0;
}
运行结果为:
1, 2, 3, 4, 5,
如何?这比使用for,或者高级一点的for_each()方便多了。
再来说说输入流迭代子吧,类istream_iterator在我看来没有什么很大的用处,似乎是因为有了输出迭代子, 为了平衡起见,就有必要产生一个输入迭代子,由此它就产生。它有三个成员变量:_M_stream为流指针, 一般指向标准输入,即cin,_M_value为读取输入后,数据缓存在该变量中,_M_ok为布尔型的标识变量。 它重载了一些迭代器必备的操作符,而成员函数中最重要的就属一个私有成员函数了,代码如下:
void _M_read()
{
_M_ok = (_M_stream && *_M_stream) ? true : false;
if (_M_ok)
{
*_M_stream >> _M_value;
_M_ok = *_M_stream ? true : false;
}
}
作用也很简单,就是当_M_stream可用时,调用_M_stream>>
,以从输入读入一个元素存储到_M_value中去。 那么该私有有函数在什么时候调用呢?在你使用++
自增时会调用,同时在构造函数中也会调用一次。 似乎不大容易理解,下面举个例子就应该能够明白了:
#include <iterator>
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
int main()
{
istream_iterator<int> iit(cin);//注意在函数函数中也调用了一次_M_read()
cout<<*iit<<endl;
cout<<*++iit<<endl;//调用了一次_M_read()
return 0;
}
运行效果为你输入一个数,它就输出该数,两次过后,程序就结束了。这里的*iit
是对operator*()
的调用, 作用是返回存储在_M_value中的元素。为什么会是两次呢?正如上面所说,在构造函数中就已经调用了一次_M_read(), 为什么要这样呢?我也不知道,呵呵,很奇怪吧?!istream_iterator没有实现operator=()
操作函数, 当然它是作用是读入,对它的赋值本身就不应该有。所以,有可能预想会有一条语句填充一个容器什么的新奇发现, 不过它确实没有这个功能,这就是为什么我会说它没有ostream_iterator那么有用的原因了。