累积整数从 C++11 中的文件中读取数据

Accumulate integers reading data from file in C++11

我想问一下当您从文件中读取整数时,accumulate 是如何工作的。 通常 accumulate 接受一个指向容器第一个位置的迭代器和一个指向同一容器最后一个位置的迭代器(例如 vector)和初始值。 如果我们需要从文件中读取数据,则编写以下代码

ifstream dataFile("ints.dat");
accumulate(istream_iterator<int>(dataFile), istream_iterator<int>(), 0);

创建的临时迭代器不是同一容器的迭代器。我不明白这是如何正确工作的,并且不会导致无限循环。 accumulate 的可能实现如下:

template<class InputIt, class T>
T accumulate(InputIt first, InputIt last, T init)
{
    for (; first != last; ++first)
    {
        init = init + *first;
    }
    return init;
}

这里不涉及容器,因为您使用的是具有特定行为的流迭代器。

当您递增 istream_iterator 时,将从基础流中读取一个值。如果在读取时发生错误(fail() returns true),则迭代器变为 end-of-stream 迭代器。

默认构造的 istream_iterator 始终是 流结束 迭代器,因此只有当 istream_iterator 上的增量运算符时,两个迭代器才会比较相等无法读取下一个值(在文件末尾,或发生错误时)。


标准中的一些相关引用:

[istream.iterator-1]

After it is constructed, and every time ++ is used, the iterator reads and stores a value of T. If the iterator fails to read and store a value of T (fail() on the stream returns true), the iterator becomes equal to the end-of-stream iterator value. The constructor with no arguments istream_iterator() always constructs an end-of-stream input iterator object, which is the only legitimate iterator to be used for the end condition. [...]

[istream.iterator-2]

Two end-of-stream iterators are always equal. An end-of-stream iterator is not equal to a non-end-of-stream iterator. [...]

这就是 C++ 的魅力:-)

要完全理解这一点,我们必须理解 typeobject 之间的区别以及符号 (++,!=) 只是函数(尽管是专门定义的)。

标准算法accumulate定义为:

  1. 取一个容器的开头 iterator
  2. 取一个iterator符号化一个容器的末端,
  3. 取初始值

在所示的实现中,expalin 的关键部分是: first != last.

这不是一个很复杂的表达式。但是幕后发生的事情却很有趣。

我们可以看到类型是 istream_iterator<int>。此类型定义了许多操作。其中一个操作是操作 ++(plus plus -or- increment -or- move to next位置)。这很容易解释:调用 ++ 就好像为迭代器 type 定义了一个函数 move_to_next()。然后当使用 ++ 时,它就像为声明的 object.

调用函数 move_to_next()

以同样的方式定义了一个特殊函数!=exclaimation equals -or- not equal)。

为了这个解释让我们重新定义它bool compare_iterators_not_equal(istream_iterator<int> lhs, istream_iterator<int> rhs)。此函数将两个 istream_iterator 对象作为参数,并评估这两个对象是否 不等于 .

现在结合这些信息...

结束迭代器对象不必是容器中的物理位置。它只需要 符号化 容器的末尾,以便在比较迭代器对象时(通过 compare_iterators_not_equal 函数 (!=))它将 return 迭代器已经到达终点。

所以第一个迭代器定义在输入流上,并不断读取下一个数据。当它到达输入的末尾时,迭代器会改变它的状态——变成一个表明它已经到达输入末尾的状态。当将处于此状态的迭代器与默认构造的迭代器( 表示 输入结束)进行比较时,比较函数知道:它是输入的结束。然后循环结束。