【问题标题】:Confused about usage of 'std::istreambuf_iterator'对“std::istreambuf_iterator”的使用感到困惑
【发布时间】:2020-01-22 05:51:55
【问题描述】:

以下是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&lt;char&gt; v( (std::istreambuf_iterator&lt;char&gt;(in)), std::istreambuf_iterator&lt;char&gt;() );,我不太明白它在做什么..为什么我们可以只使用cout&lt;&lt;&amp;v[0]打印字符串“Hello, world”
  2. 为什么 *i2 的值从“a”跳到“c”?有人能解释一下它的机制吗?

非常感谢!

【问题讨论】:

    标签: c++


    【解决方案1】:

    谁能详细说明一下代码...

    std::vector&lt;T&gt; 有一个构造函数,它在 &lt;T&gt; 上接受两个迭代器 - 一个用于范围的开头,一个用于范围的结尾。

    这个构造函数从输入流in生成一个输入流迭代器:

    std::istreambuf_iterator<char>(in)
    

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

    std::istreambuf_iterator<char>()
    

    因此,传递这对迭代器会根据从输入流中读取的数据构造一个vector&lt;T&gt;。将消耗整个流。

    为什么*i2 的表观值会从"a" 跳转到"c"

    两个迭代器都从同一个流中读取。当您增加第一个迭代器时,它会从底层流中消耗'b'。同时,i2 指的是流的第一个字符,它是在构造时没有前进的。

    一旦你增加i2,它就会向流询问下一个字符。字符'b'已经被消费了,所以下一个字符是'c'

    最后,代码引入了一个您可能忽略的小技巧:它将空终止符推入vector&lt;char&gt;,以便能够使用const char* 重载operator &lt;&lt;(...) 打印向量。

    【讨论】:

    • 另外,他如何将消息打印为&amp;v[0]? :)
    • 因为v[0]char 所以&amp;v[0]char*
    • @JonathanWakely 我知道,我要求他在回答中解释。 :)
    • @JonathanWakely char* 只是交易的一部分:代码通过手动附加'\0' 来实现一个小技巧。我认为这就是为什么 0x499... 在评论旁边放一个笑脸 :)
    【解决方案2】:

    默认构造的istreambuf_iterator 基本上是一个文件尾迭代器——也就是说,另一个迭代器只有在到达文件末尾时才会与它进行比较。

    因此,代码:

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

    ...从in 读取chars,直到第一个迭代器递增到等于第二个迭代器,这发生在(且仅当)第一个迭代器到达文件末尾时(字符串流,在此案子)。简而言之,它将文件的全部内容复制到向量中。

    打印“hello world”部分稍微简单一些:ostream 对char * 有一个operator&lt;&lt; 重载,它假定char * 指向一个C 风格的字符串,所以它应该打印出整个字符串这是指向的。由于他们已经使用push_back'\0' 添加到字符串中,这使其成为C 风格的字符串。

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

    因此,每当您增加 either 迭代器(或 any 迭代器到同一流中)时,它都会增加当前读取位置。所以,你从i1i2 开始都指向流的开头。然后你增加i1。这会增加读取位置,并将b 读入i1,因此当您取消引用i1 时,这就是您将得到的。当您增加i2 时,会再次移动读取位置,并将c 读入i2,因此取消引用i2 将得到c

    使用两个(或更多)迭代器不会改变流的性质——每次你将 any 迭代器增加到同一个流中时,都会读取 下一个项目 来自该流 - 并且“下一项”始终由流本身确定,基于其 一个 读取位置。

    【讨论】:

      猜你喜欢
      • 2011-05-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-23
      • 2023-02-05
      相关资源
      最近更新 更多