先来看个例子:
ifstream inputFile("ints.dat");
list<int> data(istream_iterator<int>(inputFile), istream_iterator<int>());
上面的这两行代码,貌似是将两个 isteam_iterator 迭代器传给list容器的构造函数,从而将文件中的数据拷贝到容器中。
但是,结果真的如我们所料吗?首先我们看下下面的代码。
int f(double d);
int f(double (d));
int f(double);
这三行代码效果是相同的,都是定义了一个函数,函数的返回值的int类型,参数是double类型。
下面的这行代码也是定义了一个函数,函数 g 以指向函数的指针为参数
int g( dlouble (*pf)() );
(*pf)()
是一个指向一个不带任何参数的函数的指针,返回值为double类型,返回值做了 函数 g 的参数。
那么下面的这个函数申明和上面表达了同样的含义。
int g( dlouble pf() );
如果我们将参数名称省略。
int g( dlouble () );
那么这个函数和上面的 int f(double (d));
有什么区别呢?
我们可以看到,函数 f 的括号是在实参的两边,括号存在和不存在效果是一样的,但是函数 g 则不同,存在一个空的括号,根据推导,这个空的括号是有具体意义的,是存在一个函数指针参数的。
接下来,我们看下最开始的问题。
ifstream inputFile("ints.dat");
list<int> data(istream_iterator<int>(inputFile), istream_iterator<int>());
那么我们就能够很明显的看出,第二行代码是申明了一个名称为data
的函数。函数返回值类型为 list<int>
,函数有两个参数。
- 第一个参数名称为 inputFile,类型为
istream_iterator<int>
- 第二个参数没有名称。类型是指向不带参数的函数的指针,该函数的返回值是
istream_iterator<int>
所以,上面的代码不会达到我们逾期的效果。
就跟下面的例子一样,是我们经常犯的错误,下面第二行代码并没有定义一个Widget的对象,而是申明了一个,没有参数,返回值类型为Widget,名称为w的函数。
class Widget{...};
Widget w();
按照下面的方式解决上述的问题。让代码不要出现二义性。
ifstream inputFile("ints.dat");
istream_iterator<int> begin(inputFile);
istream_iterator<int> end;
list<int> data(begin, end);
我们再来看下下面的例子:
#include<iostream>
#include <fstream>
#include <ctime>
#include <iterator>
#include <cassert>
using namespace std;
int main()
{
ifstream inputData("intdata.dat");
assert(inputData.is_open());
inputData.unsetf(ios::skipws);
time_t t1 = time(NULL);
string data((istream_iterator<char>(inputData)), istream_iterator<char>());
time_t t2 = time(NULL);
cout << t1 << " " << t2 << endl; //1634635857 1634635866
time_t t3 = time(NULL);
string data2((istreambuf_iterator<char>(inputData)), istreambuf_iterator<char>());
time_t t4 = time(NULL);
cout << t3 << " " << t4 << endl; //1634635923 1634635923
return 0;
}
上面的例子有两种从文件读取字符并构建了一个string
的对象,前一种使用了 istream_iterator
后一种使用的是istreambuf_iterator
,两者的区别也是显而易见的。
istream_iterator
较istreambuf_iterator
耗时更久istream_iterator
默认是忽略字符中的空格的- 需要设置
inputData.unsetf(ios::skipws);
因此,如果需要从输入流中逐个读取字符,istreambuf_iterator
是个不错的选择,就不必要进行格式化输入,因为 istream_iterator
在调用其 operator <<
时其实是进行了格式化的输入。但istreambuf_iterator
从一个输入流中 stream s
读取下一个字符是通过 s.rdbuf()->sgetc()
完成的。 如果追求输入的效率,那么选择istreambuf_iterator
。
同样的,输出的时候也可以选择 ostreambuf_iterator
。