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

Accumulate integers reading data from file in C++11

本文关键字:读取 数据 整数 文件 C++11      更新时间:2023-10-16

我想问一下当你从文件中读取整数时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()返回true(,则迭代器将成为流结束迭代器。

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


标准中的一些相关引用:

[istream.iterator-1]

建成后,每次++使用时,迭代器读取并存储值T。如果迭代器无法读取和存储T的值 (fail()流返回 true(,迭代器将等于流结束迭代器值。不带参数的构造函数始终istream_iterator()构造流结束输入迭代器对象,该对象是 用于结束条件的唯一合法迭代器。[...]

[istream.iterator-2]

两个流结束迭代器始终相等。流结束迭代器不等于非流结束迭代器。[...]

这就是C++的美妙之处:-(

为了完全理解这一点,我们必须理解类型和对象之间的区别,以及符号(++!=(只是函数(尽管是特殊定义的(。

标准算法accumulate定义为:

  1. iterator一个容器的开头,
  2. 拿一个象征容器末端的iterator
  3. 获取初始值

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

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

如我们所见,类型是一个istream_iterator<int>.此类型定义了许多操作。其中一个操作是操作++(加上加- 或 -递增- 或 -移动到下一个位置(。 这很容易解释:++的调用就像为迭代器类型定义一个函数move_to_next()。然后,当使用++时,就像为声明的对象调用函数move_to_next()一样。

以同样的方式,定义了一个特殊的函数!=(感叹等于- 或 -不等于(。

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

现在结合这些信息...

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

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