zoukankan      html  css  js  c++  java
  • 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, " "); 
     除了“连接至标准输入”外,还可以连接至其他设备,如文件: 
     

    [cpp] view plaincopy
     
    1. #include <fstream>   
    2.  using namespace std;   
    3.  ifstream in_file("in.txt");   
    4.  ofstream out_file("in.txt");   
    5.  if ( !in_file || !out_file )   
    6.  {   
    7.          cerr << "failed to open the necessary file! /n";   
    8.           return -1;   
    9.  }   
    10.  istream_iterator<string> is(in_file);   
    11.  istream_iterator<string> eof;   
    12.  ostream_iterator<string> os(out_file, " ");   



    ***********************************************************************************************

    [cpp] view plaincopy
     
    1. #include <iostream>     
    2. #include <iterator>     
    3. #include <string>     
    4. #include <vector>     
    5. #include <fstream>     
    6. #include <algorithm>     
    7. using namespace std;    
    8. int main()    
    9. {    
    10.     // 1. 标准输入输出操作。     
    11.     istream_iterator<string> is(cin);    
    12.     istream_iterator<string> eof;    
    13.     vector<string> text;    
    14.     // 将标准输入的内容复制至text中。  由于使用的是vector,故使用back_inserter()     
    15.     copy(is, eof, back_inserter(text));      
    16.     // do something.     
    17.     sort(text.begin(), text.end());    
    18.     // 输出至标准输出。     
    19.     ostream_iterator<string> os(cout, " ");    
    20.     copy(text.begin(), text.end(), os);    
    21.     // 2. 非标准输入输出操作:文件读写操作。     
    22.     ifstream in_file("in.txt");    
    23.     ofstream out_file("in.txt");    
    24.     if ( !in_file || !out_file )    
    25.     {    
    26.         cerr << "failed to open the necessary file! /n";    
    27.         return -1;    
    28.     }    
    29.     istream_iterator<string> is2(in_file);    
    30.     istream_iterator<string> eof2;    
    31.     vector<string> text2;    
    32.     copy(is2, eof2, back_inserter(text2));    
    33. sort(text2.begin(), text2.end());    
    34.     ostream_iterator<string> os2(out_file, " ");    
    35.     copy(text2.begin(), text2.end(), os2);    
    36.     return 0;    
    37. }    



    ************************************************************************************


    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. 正确的完整代码

    [cpp] view plaincopy
     
    1. #include <iostream>  
    2. #include <iterator>  
    3. #include <fstream>  
    4. #include <vector>  
    5. #include <algorithm>  
    6. using namespace std;  
    7.   
    8.   
    9. int main()  
    10. {  
    11.     ifstream ifs("test.txt");  
    12.     istream_iterator<string> ibeg(ifs);  
    13.     istream_iterator<string> iend;  
    14.     vector<string> vec(ibeg, iend);  
    15.   
    16.   
    17.     copy(vec.begin(), vec.end(),ostream_iterator<string>(cout, " "));  
    18.     return 0;  
    19. }  




    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是我故意这样写的,只是为了让大家明白这个名字随便起都行)

    [cpp] view plaincopy
     
    1. istream_iterator<T> eoff ;  

    发现eoff的私有变量中_Myistr为0x000000000;

    再看看一个定义: (注意:test.txt的内容为10(EOF) )

    [cpp] view plaincopy
     
    1. ifstream infile("f:\test.txt");  
    2. istream_iterator<int> input(infile);  

    再用vs2008调试时查看:

    大家发现没有:input变量的私有成员_Myistr不为0了! 且私有成员_Myval正好为10(即文件中的第一个整型数)

    现在在执行下一行代码:

    [cpp] view plaincopy
     
    1. ++input;  

    再用VS2008看看input的成员:

    ++input后,其私有成员_Myistr变为0x00000000了!和之前定义的eoff变量一样了!

    再执行下一行看看会输出什么:

    [cpp] view plaincopy
     
    1. 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

    完整程序如下:

    [cpp] view plaincopy
     
    1. #include <iostream>  
    2. #include <vector>  
    3. #include <fstream>  
    4. #include <iterator> //istream_iterator,ostream_iterator,back_inserter  
    5. #include <algorithm> //copy  
    6. #include <Windows.h> //system  
    7. using namespace std;  
    8. int main()  
    9. {  
    10.     istream_iterator<int> eoff;  
    11.     ifstream infile("f:\test.txt"); //运行前,请让f:\test.txt里面只有一个整数  
    12.     istream_iterator<int> input(infile);  
    13.     cout<<"the first element:"<<*input<<endl;  
    14.     ++input;  
    15.     cout<<(input == eoff ? "EOF" : "others")<<endl;  
    16.   
    17.     cout<<"*******************"<<endl;  
    18.     cout<<"请输入整数,按ctrl+z结束输入:"<<endl;  
    19.     vector<int> ivec;  
    20.     copy(istream_iterator<int>(cin),istream_iterator<int>(),back_inserter(ivec));  
    21.     //下句为将ivec内容输出屏幕  
    22.     copy(ivec.begin(),ivec.end(),ostream_iterator<int>(cout," "));  
    23.     system("pause");  
    24. }  

    ps: istream_iterator 和 ostream_iterator 都没有定义自减运算,即 --input; 是错误的!

    2. 注意了如果对于istream_iterator<int> 型,如果文件里面是为字母的话,input会如何呢? 

    在此之前,请把f: est.txt的加一个字母看什么情况 即内容为: 10   sfd(EOF)

    [cpp] view plaincopy
     
    1. istream_iterator<int> eoff;  
    2. ifstream infile("f:\test.txt"); //运行前,请让f:\test.txt里面只有一个整数  
    3. istream_iterator<int> input(infile);  
    4. cout<<"the first element:"<<*input<<endl;  
    5. ++input;  


    运行这几句后,istream_iterator<int> input(infile)应该只能指向整型,但现在为字母了,会如何呢?

    我们看看现在的input的成员:

    input遇到字母时,_Myistr也变为0x00000000了。那么是不说

    [cpp] view plaincopy
     
    1. 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为左值为:

    例如:

    [cpp] view plaincopy
     
    1. ostream_iterator<int> output(cout," : ");  
    2. *output = 5;  
    3. *output = 6;  

    或者这样写

    [cpp] view plaincopy
     
    1. ostream_iterator<int> output(cout," : ");  
    2. *output++ = 5;  
    3. *output++ = 6;  

    其结果都是:5 : 6

    output每次解引用 *output后赋值后,都会使自己自加1  。

    也就是说不用自己使用 *output++ 的方法了。

    总之:

    这两句是最好用的了:

    [cpp] view plaincopy
     
    1. copy(istream_iterator<int>(cin),istream_iterator<int>(),back_inserter(ivec));  
    2. //下句为将ivec内容输出屏幕  
    3. copy(ivec.begin(),ivec.end(),ostream_iterator<int>(cout," "));  

    输入那句更好的是

    vector<int> ivec(istream_iterator<int>(cin),istream_iterator<int>());

    这句更简洁.

    若写的有问题,请各位大侠指教。

    转载请注明出处.

  • 相关阅读:
    彻底理解数字图像处理中的卷积-以Sobel算子为例
    CSK & KCF(tracking)
    内积、标量积、点积、点乘
    C++拷贝构造函数详解
    从RGB色转为灰度色算法
    混合高斯背景建模原理及实现
    单高斯背景建模
    计算机视觉目标跟踪的算法分类
    SVM:从理论到OpenCV实践
    HOG特征(Histogram of Gradient)学习总结
  • 原文地址:https://www.cnblogs.com/johnnyflute/p/3714188.html
Copyright © 2011-2022 走看看