对于' std :: istreambuf_iterator'的使用感到困惑

时间:2014-12-10 17:06:06

标签: c++

以下是an example from cppreference.com

The Code is:
#include <vector>
#include <sstream>
#include <iostream>
#include <iterator>

int main()
{
// typical use case: an input stream represented as a pair of iterators
std::istringstream in("Hello, world");
std::vector<char> v( (std::istreambuf_iterator<char>(in)),
                      std::istreambuf_iterator<char>() );
std::cout << "v has " << v.size() << " bytes. ";
v.push_back('\0');
std::cout << "it holds \"" << &v[0] << "\"\n";


// demonstration of the single-pass nature
std::istringstream s("abc");
std::istreambuf_iterator<char> i1(s), i2(s);
std::cout << "i1 returns " << *i1 << '\n'
          << "i2 returns " << *i2 << '\n';
++i1;
std::cout << "after incrementing i1, but not i2\n"
          << "i1 returns " << *i1 << '\n'
          << "i2 returns " << *i2 << '\n';
++i2; // this makes the apparent value of *i2 to jump from 'a' to 'c'
std::cout << "after incrementing i2, but not i1\n"
          << "i1 returns " << *i1 << '\n'
          << "i2 returns " << *i2 << '\n';

}

我有两个问题:

  1. 有人可以详细说明代码std::vector<char> v( (std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>() );,我不太明白它在做什么......为什么我们只能使用cout<<&v[0]打印字符串“Hello,world”
  2. 为什么* i2的apprent值跳“a”到“c”?有人可以解释它的机制吗?
  3. 非常感谢!

2 个答案:

答案 0 :(得分:14)

  

有人可以详细说明代码......

std::vector<T>有一个构造函数,在<T>上有两个迭代器 - 一个用于开头,另一个用于范围的结尾。

此构造函数从输入流in生成输入流迭代器:

std::istreambuf_iterator<char>(in)

您可以访问其元素,直到到达流的末尾。一旦到达流的末尾,迭代器就等同于使用默认构造函数创建的迭代器:

std::istreambuf_iterator<char>()

因此,传递这对迭代器会从输入流中读取的数据构造vector<T>。整个流将被消耗。

  

为什么*i2的apprent值会跳至"a""c"

两个迭代器都从同一个流中读取。当您递增第一个迭代器时,它会从基础流中消耗'b'。与此同时,i2指的是流的第一个字符,它在构建时没有前进。

一旦递增i2,它会向流询问下一个字符。字符'b'已被消耗,因此下一个字符为'c'

最后,代码提取了一个您可能忽略的小技巧:它将空终止符推送到vector<char>,以便能够使用const char* operator <<(...)重载来打印向量}}

答案 1 :(得分:5)

默认构造的istreambuf_iterator基本上是一个文件结束迭代器 - 也就是说,只有当它到达文件末尾时,另一个迭代器才会比较它。

因此,代码:

std::vector<char> v( (std::istreambuf_iterator<char>(in)),
                      std::istreambuf_iterator<char>() );

...从char读取in,直到第一个迭代器增加到等于第二个迭代器,这发生在第一个迭代器到达文件末尾时(并且仅当) stringstream,在这种情况下)。简而言之,它将文件的全部内容复制到矢量中。

印刷&#34;你好世界&#34; part有点简单:ostream对operator<<有一个char *重载,假设char *指向一个C风格的字符串,所以它应该打印出整个字符串&#39} ; s指着。由于他们已经完成了push_back向字符串添加'\0',因此它会成为C风格的字符串。

第二部分展示了即使你有两个迭代器进入流,你仍然只有一个流,并在该流中有一个读取位置。同时,每个迭代器都保存从流中读取的最新项的副本。

因此,无论何时将 迭代器(或任何迭代器)递增到同一个流中,它都会递增当前读取位置。因此,您从i1i2开始,两者都指向流的开头。然后你增加i1。这会增加阅读位置,并将b读入i1,因此当您取消引用i1时,就会获得您所获得的内容。当您递增i2时,会再次移动阅读位置,并将c读取到i2,因此取消引用i2会给c

简而言之,使用两个(或更多)迭代器并不会改变流的性质 - 每次将任何迭代器增加到同一个流中时,它会读取<来自该流的em> next item - 以及&#34; next item&#34;始终由流本身根据其一个读取位置确定。