C++ iostream迭代器

       虽然iostream类型不是容器,但标准库定义了可以用于这些IO类型对象的迭代器。istream_iterator读取输入流,ostream_iterator向一个输入流写数据。这些迭代器将它们对应的流当做一个特定类型的元素序列来处理。通过使用流迭代器,我们可以用泛型算法从流对象读取数据以及向其写入数据。
 

istream_iterator操作
       当创建一个流迭代器时,必须指定迭代器将要读写的对象类型。一个istream_iterator使用>>来读取流。因此,istream_iterator要读取的类型必须定义了输入运算符。当创建一个istream_iterator时,我们可以将它绑定到一个流。当然,我们还可以默认初始化迭代器,这样就创建了一个可以当作尾后使用的迭代器。

istream_iterator<int>int_it(cin);      //从cin读取int
istream_iterator<int>int_eof;          //尾后迭代器
ifstream in("afile");
istream_iterator<string>str_it(in);   //从"afile"读取字符串

下面是一个用istream_iterator从标准输入读取数据,存入一个vector的例子:

istream_iterator<int> in_iter(cin);   //从cin读取int
istream_iterator<int> 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<int> in_iter(cin),eof;   //从cin读取int
vector<int>vec(in_iter,eof);              //从迭代器范围构造vec

       本例中我们一对表示元素范围的迭代器来构造vec。这两个迭代器是istream_iterator,这意味着元素范围是通过从关联的流中读取数据获得的。这个构造函数从cin中读取数据,直至遇到文件尾或者遇到一个不是int的数据为止。从流中读取的数据被用来构造vec。


使用算法操作流迭代器
由于算法使用迭代器操作来处理数据,而迭代器又至少支持某些迭代器操作,因此,我们至少可以用某些算法来操作流迭代器。下面是一个例子,用一对istream_iterator来调用accumulate:

istream_iterator<int> in(cin),eof;
cout<<accumulate(in,eof,0)<<endl;

此调用会计算出标准输入读取的值的和。如果输入为:
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<T> out(os);       //out将类型为T的值写到输出流os中
ostream_iterator<T> out(os,d);     //out将类型为T的值写到输出流os中,每个值后面都输出一个d。
out = val         //用<<运算符将val写入到out所绑定的ostream中。val的类型必须与out可写的类型兼容
*out,++out,out++  //这些运算符是存在的,但不对out做任何事情。每个运算符都返回out

我们可以用ostream_iterator来输出值的序列:

ostream_iterator<int> out_iter(cout," ");
for(auto e : vec)
       *out_iter++=e;    //赋值语句实际上将元素写到cout
cout<<endl;

       此程序将vec中的每个元素写到cout,每个元素后加一个空格。每次向out_iter赋值时,写操作就会被提交。
       值得注意的是,当我们向out_iter赋值时,可以忽略解引用和递增运算。即,循环可以重写成下面的样子:

for(auto e : vec)
    out_iter=e;   //赋值语句将元素写到cout
cout<<endl;

       运算符*和++实际上对ostream_iterator对象不做任何事情,因此忽略它们对我们的程序没有任何影响。但是,推荐第一种形式。在这种写法中,流迭代器的使用与其他迭代器的使用保持一致。如果想将此循环改为操作其他迭代器类型,修改起来非常容易。而且,对于读者来说,此循环的行为更为清晰。
可以通过copy来打印vec中的元素,这样编写循环更为简单:

copy(vec.begin(),vec.end(),out_iter);
cout<<endl;


使用流迭代器处理类类型
       我们可以为任何定义了输入运算符(>>)的类型创建istream_iterator对象。类似的,只要类型有输出运算符(<<),我们就可以为其定义ostream_iterator。比如一个Counter类,既有输入运算符也有输出运算符,因此可以使用IO迭代器。如下所示

istream_iterator<Counter> Cou_iter(cin),eof;
ostream_iterator<Counter> out_iter(cout,"\n");

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值