stream_iterator、ostream_iterator 使用初探
STL定义了供输入及输出的iostream iterator类,称为 istream_iterator和ostream_iterator,分别支持单一型别的元素的读取和写入。
使用方法:
1.包含头文件: #include <iterator> using namespace std;
2.像使用其他iterator一样使用istream_iterator和 ostream_iterator。如:
使用一对“连接至标准输入”的iterator用于标示元素范围:
// 将is定义为一个“连接至标准输入装置”的istream_iterator
istream_iterator<string> is(cin);
// 定义istream_iterator时不为它指定istream对象,它即代表了end-of-file。
istream_iterator<string> eof;
ostream_iterator<string> os(cout, " ");
除了“连接至标准输入”外,还可以连接至其他设备,如文件:
- #include <fstream>
- using namespace std;
- ifstream in_file("in.txt");
- ofstream out_file("in.txt");
- if ( !in_file || !out_file )
- {
- cerr << "failed to open the necessary file! /n";
- return -1;
- }
- istream_iterator<string> is(in_file);
- istream_iterator<string> eof;
- ostream_iterator<string> os(out_file, " ");
***********************************************************************************************
- #include <iostream>
- #include <iterator>
- #include <string>
- #include <vector>
- #include <fstream>
- #include <algorithm>
- using namespace std;
- int main()
- {
- // 1. 标准输入输出操作。
- istream_iterator<string> is(cin);
- istream_iterator<string> eof;
- vector<string> text;
- // 将标准输入的内容复制至text中。 由于使用的是vector,故使用back_inserter()
- copy(is, eof, back_inserter(text));
- // do something.
- sort(text.begin(), text.end());
- // 输出至标准输出。
- ostream_iterator<string> os(cout, " ");
- copy(text.begin(), text.end(), os);
- // 2. 非标准输入输出操作:文件读写操作。
- ifstream in_file("in.txt");
- ofstream out_file("in.txt");
- if ( !in_file || !out_file )
- {
- cerr << "failed to open the necessary file! /n";
- return -1;
- }
- istream_iterator<string> is2(in_file);
- istream_iterator<string> eof2;
- vector<string> text2;
- copy(is2, eof2, back_inserter(text2));
- sort(text2.begin(), text2.end());
- ostream_iterator<string> os2(out_file, " ");
- copy(text2.begin(), text2.end(), os2);
- return 0;
- }
************************************************************************************
istream_iterator常见错误
1. 错误原码
以下原代码不能通过编译:
ifstream ifs("test.txt");
istream_iterator<string> ibeg(ifs);
istream_iterator<string> iend();
vector<string> vec(ibeg, iend);
对于vec的构造编译出错:
error: no matching function for call to `std::vector<std::string, std::allocator<std::string> >::vector(std::istream_iterator<std::string, char, std::char_traits<char>, ptrdiff_t>&, std::istream_iterator<std::string, char, std::char_traits<char>, ptrdiff_t> (&)())'
原来它把iend当作了一个函数。去掉iend后面的括号就行了:
2. 正确的完整代码
- #include <iostream>
- #include <iterator>
- #include <fstream>
- #include <vector>
- #include <algorithm>
- using namespace std;
- int main()
- {
- ifstream ifs("test.txt");
- istream_iterator<string> ibeg(ifs);
- istream_iterator<string> iend;
- vector<string> vec(ibeg, iend);
- copy(vec.begin(), vec.end(),ostream_iterator<string>(cout, "\n"));
- return 0;
- }
3. 直接内嵌出错
就像在copy函数中一样,并不需要定义ibeg, iend, 应该可以在vector的构造函数中嵌入,如下:
vector<string> vec(istream_iterator<string>(ifs),istream_iterator<string>);
以上代码当在copy中调用vec.begin(), vec.end()时,就会编译报错:
error: request for member `begin' in `vec', which is of non-class type `std::vector<std::string, std::allocator<std::string> > ()(std::istream_iterator<std::string, char, std::char_traits<char>, ptrdiff_t>, std::istream_iterator<std::string, char, std::char_traits<char>, ptrdiff_t>)'
error: request for member `end' in `vec', which is of non-class type `std::vector<std::string, std::allocator<std::string> > ()(std::istream_iterator<std::string, char, std::char_traits<char>, ptrdiff_t>, std::istream_iterator<std::string, char, std::char_traits<char>, ptrdiff_t>)'
看来编译器将vec当作了一个函数,而不是一个vector类。
其中istream_iterator<string>(ifs)
的括号被编译器忽略了,成为
vector<string> vec(istream_iterator<string> ifs,
istream_iterator<string>);
等同于:
vector<string> fun(istream_iterator<string> x,
istream_iterator<string> y);
4. 访止编译器误解
就像在加减乘除中用括号指定运算顺序一样,这里也要用括号将构造的临时参数括起来,访止编译器将它们误解为函数中的参数声明。
同时还要修正一个错误,vec构造函数中的第二个参数构造是错误的,应该加个括号构造一个临时变量。不然对
istream_iterator<string>);
报错:
error: expected primary-expression before ')' token
因为它只是一个类型声明,而不是一个基本表达式(primary-expression)。
正确的方法如下:
vector<string> vec((istream_iterator<string>(ifs)),
istream_iterator<string>());
或
vector<string> vec((istream_iterator<string>(ifs)),
(istream_iterator<string>()));
该种方法虽然可行,但还是不用为好,以免某些编译器不支持,同时也增加代码理解难度,而且在更复杂的情形中,这一招也无法解决问题。还是第5种简化方法比较合适
提示:不管需不需要,稍微复杂一点的表达式都用括号括起来。免得人阅读时出错,或者编译器理解时出错。
5. 另一种简化方法
ibeg, iend的定义可以合为一行,可能比内嵌式表达方法更清晰:
istream_iterator<string> ibeg(ifs), iend;
vector<string> vec(ibeg, iend);
http://blog.csdn.net/rickliuxiao/article/details/6201835
http://www.cppblog.com/jinq0123/archive/2007/12/12/istream_iterator_ErrorMsg.html
istream_iterator 在<iterator>头文件的定义中
定义istream_iterator变量的方法为
istream_iterator<T> in(strm); (其中T指明此istream_iterator的输入类型 , strm为istream_iterator指向的流)
提供了输入操作符(>>)和 输出操作符 (<<)的任何类型都可以创建 istream_iterator 对象和ostream_iteratorcfq对象,即对自己的类重载了这两个函数:
istream &operator >> (istream &is, &MyClass c);
和 ostream &operator << (ostream &os , const &MyClass c);
1. 若strm为空时,即比如istream<T> in();时, 此时变量in 就相当于指向EOF标志的iterator了
如图如下定义: (下文的eoff是我故意这样写的,只是为了让大家明白这个名字随便起都行)
- istream_iterator<T> eoff ;
发现eoff的私有变量中_Myistr为0x000000000;
再看看一个定义: (注意:test.txt的内容为10(EOF) )
- ifstream infile("f:\\test.txt");
- istream_iterator<int> input(infile);
再用vs2008调试时查看:
大家发现没有:input变量的私有成员_Myistr不为0了! 且私有成员_Myval正好为10(即文件中的第一个整型数)
现在在执行下一行代码:
- ++input;
再用VS2008看看input的成员:
++input后,其私有成员_Myistr变为0x00000000了!和之前定义的eoff变量一样了!
再执行下一行看看会输出什么:
- cout<<(in == eoff ? "EOF" : "others")<<endl;
显然此时的in == eoff 成立,结果输出的是 "EOF"
现在我们知道了copy(input,eoff,back_inserter(ivec)这么用法的原因了吧。 因为copy函数是通过input先与eoff比较是否相等,若不等则将其解引用(*input)插入到ivec的最后
然后再自加1,再与eoff比较. 直到与eoff比较相等时结束! 所以用未用流初始化的istream_iterator作为哨兵.
copy(istream_iterator<int>(cin),istream_iterator<int>(),back_inserter(ivec)也是一样的情况。 需要结束时按下ctrl+z产生EOF标志 ^z
完整程序如下:
- #include <iostream>
- #include <vector>
- #include <fstream>
- #include <iterator> //istream_iterator,ostream_iterator,back_inserter
- #include <algorithm> //copy
- #include <Windows.h> //system
- using namespace std;
- int main()
- {
- istream_iterator<int> eoff;
- ifstream infile("f:\\test.txt"); //运行前,请让f:\\test.txt里面只有一个整数
- istream_iterator<int> input(infile);
- cout<<"the first element:"<<*input<<endl;
- ++input;
- cout<<(input == eoff ? "EOF" : "others")<<endl;
- cout<<"*******************"<<endl;
- cout<<"请输入整数,按ctrl+z结束输入:"<<endl;
- vector<int> ivec;
- copy(istream_iterator<int>(cin),istream_iterator<int>(),back_inserter(ivec));
- //下句为将ivec内容输出屏幕
- copy(ivec.begin(),ivec.end(),ostream_iterator<int>(cout,"\t"));
- system("pause");
- }
ps: istream_iterator 和 ostream_iterator 都没有定义自减运算,即 --input; 是错误的!
2. 注意了如果对于istream_iterator<int> 型,如果文件里面是为字母的话,input会如何呢?
在此之前,请把f:\test.txt的加一个字母看什么情况 即内容为: 10 sfd(EOF)
- istream_iterator<int> eoff;
- ifstream infile("f:\\test.txt"); //运行前,请让f:\\test.txt里面只有一个整数
- istream_iterator<int> input(infile);
- cout<<"the first element:"<<*input<<endl;
- ++input;
运行这几句后,istream_iterator<int> input(infile)应该只能指向整型,但现在为字母了,会如何呢?
我们看看现在的input的成员:
input遇到字母时,_Myistr也变为0x00000000了。那么是不说
- cout<<(input == eoff ? "EOF" : "others")<<endl;
也会输入“EOF”,即input == eoff呢? 答案确实是肯定的!
其实此时的cin.good()也为false了. 大家可以加一行代码试试:cout<<cin.good()<<endl;
现在我们知道了,当只需要整型时,使用istream_iterator<int> (cin)输入时,也可以输入一个非int型的字母来终结输入。
对于ostream_iterator<T> ouput(strm,"xxx");也是一样,只是现在的output为左值为:
例如:
- ostream_iterator<int> output(cout," : ");
- *output = 5;
- *output = 6;
或者这样写
- ostream_iterator<int> output(cout," : ");
- *output++ = 5;
- *output++ = 6;
其结果都是:5 : 6
output每次解引用 *output后赋值后,都会使自己自加1 。
也就是说不用自己使用 *output++ 的方法了。
总之:
这两句是最好用的了:
- copy(istream_iterator<int>(cin),istream_iterator<int>(),back_inserter(ivec));
- //下句为将ivec内容输出屏幕
- copy(ivec.begin(),ivec.end(),ostream_iterator<int>(cout,"\t"));
输入那句更好的是
vector<int> ivec(istream_iterator<int>(cin),istream_iterator<int>());
这句更简洁.
若写的有问题,请各位大侠指教。
转载请注明出处.
stream_iterator、ostream_iterator 使用初探的更多相关文章
- STL 迭代器适配器(iterator adapter)
iterator adapter graph LR iterator --- reverse_iterator iterator --- Insert_iterator iterator --- io ...
- 初探领域驱动设计(2)Repository在DDD中的应用
概述 上一篇我们算是粗略的介绍了一下DDD,我们提到了实体.值类型和领域服务,也稍微讲到了DDD中的分层结构.但这只能算是一个很简单的介绍,并且我们在上篇的末尾还留下了一些问题,其中大家讨论比较多的, ...
- CSharpGL(8)使用3D纹理渲染体数据 (Volume Rendering) 初探
CSharpGL(8)使用3D纹理渲染体数据 (Volume Rendering) 初探 2016-08-13 由于CSharpGL一直在更新,现在这个教程已经不适用最新的代码了.CSharpGL源码 ...
- 从273二手车的M站点初探js模块化编程
前言 这几天在看273M站点时被他们的页面交互方式所吸引,他们的首页是采用三次加载+分页的方式.也就说分为大分页和小分页两种交互.大分页就是通过分页按钮来操作,小分页是通过下拉(向下滑动)时异步加载数 ...
- JavaScript学习(一) —— 环境搭建与JavaScript初探
1.开发环境搭建 本系列教程的开发工具,我们采用HBuilder. 可以去网上下载最新的版本,然后解压一下就能直接用了.学习JavaScript,环境搭建是非常简单的,或者说,只要你有一个浏览器,一个 ...
- .NET文件并发与RabbitMQ(初探RabbitMQ)
本文版权归博客园和作者吴双本人共同所有.欢迎转载,转载和爬虫请注明原文地址:http://www.cnblogs.com/tdws/p/5860668.html 想必MQ这两个字母对于各位前辈们和老司 ...
- React Native初探
前言 很久之前就想研究React Native了,但是一直没有落地的机会,我一直认为一个技术要有落地的场景才有研究的意义,刚好最近迎来了新的APP,在可控的范围内,我们可以在上面做任何想做的事情. P ...
- 【手把手教你全文检索】Apache Lucene初探
PS: 苦学一周全文检索,由原来的搜索小白,到初次涉猎,感觉每门技术都博大精深,其中精髓亦是不可一日而语.那小博猪就简单介绍一下这一周的学习历程,仅供各位程序猿们参考,这其中不涉及任何私密话题,因此也 ...
- Key/Value之王Memcached初探:三、Memcached解决Session的分布式存储场景的应用
一.高可用的Session服务器场景简介 1.1 应用服务器的无状态特性 应用层服务器(这里一般指Web服务器)处理网站应用的业务逻辑,应用的一个最显著的特点是:应用的无状态性. PS:提到无状态特性 ...
随机推荐
- kettle Argument, Parameter, Variable
1. Argument, Parameter, Variable 的区别 a.Argument作为位置参数不能复用,而其他2个可以根据名称重复使用 b. Argument, Parameter作用域局 ...
- iOS类似QQ好友展开和合并列表的实现代码
其实原理就是好友列表合上的时候,将这组的cell数设置为0,展开的时候,在变成原来的,就是这么简单 -(); }
- IOS-7步学会用代理
代理:又叫委托 自己不能去办的事委托给别人去办 之前学过的 UIAlertView UITextField都是使用了代理 反向传值代理 代理Block 写代理的步骤 需要帮忙的人(请求帮代饭的人) 1 ...
- 【转】图解SQL的各种连接join
原帖地址:http://www.nowamagic.net/librarys/veda/detail/936 图解SQL的各种连接join 让你对SQL的连接一目了然 在 2011年12月22日 那天 ...
- STL的简介
Standard Template Library,(标准模板库)<来自百度百科的整理> ————可复用性(reusability) STL是基于模板,内联函数的使用使得生成的代码短小高效 ...
- 以boost::function和boost:bind取代虚函数
转自:http://blog.csdn.net/Solstice/archive/2008/10/13/3066268.aspx 这是一篇比较情绪化的blog,中心思想是“继承就像一条贼船,上去就下不 ...
- 程序员面试题精选100题(16)-O(logn)求Fibonacci数列[算法]
作者:何海涛 出处:http://zhedahht.blog.163.com/ 题目:定义Fibonacci数列如下: / 0 n=0 f(n)= ...
- ASP.net后台弹出消息对话框的方法!【转】
在winform后台,我们通过MessageBox.show(“消息")的方式来返回后台信息,在webform后台,我们通过Response.write(”消息")来返 ...
- 在LaTeX中利用preview宏包和tikz宏包生成单图pdf
有时候我们利用tikz宏包画出的图片后,只想生成一个单图pdf,而且pdf的页面大小与图片相同,以便于以后再次用latex插入. 可以与preview宏包进行搭配,页面大小由图像大小决定,可以通过改变 ...
- Mac OS X平台上Java环境的配置
最近换了工作,以前是做c/c++的,但是现在公司的主打产品是使用Java开发,为了以后维护代码,现在开始抽空学习一下Java相关的内容. 在学习之前,首先需要搭建各种平台的开发环境,而我选用的操作系统 ...