【问题标题】:C++ streams confusion: istreambuf_iterator vs istream_iterator?C++ 流混淆:istreambuf_iterator 与 istream_iterator?
【发布时间】:2012-05-20 19:07:54
【问题描述】:

istreambuf_iteratoristream_iterator 有什么区别? 一般来说,流和流缓冲区有什么区别? 我真的找不到任何明确的解释,所以决定在这里问。

【问题讨论】:

标签: c++ istream streambuf


【解决方案1】:

IOstreams 使用 streambufs 作为输入/输出的源/目标。实际上,streambuf-family 完成了有关 IO 的所有工作,而 IOstream-family 仅用于格式化和 to-string / from-string 转换。

现在,istream_iterator 接受一个模板参数,该参数说明来自 streambuf 的未格式化字符串序列应格式化为什么格式,例如 istream_iterator<int> 会将所有传入文本(空格分隔)解释为 ints。

另一方面,istreambuf_iterator 只关心原始字符,并直接遍历它所传递的 istream 的关联流缓冲区。

通常,如果您只对原始字符感兴趣,请使用istreambuf_iterator。如果您对格式化输入感兴趣,请使用istream_iterator

我所说的所有内容也适用于ostream_iteratorostreambuf_iterator

【讨论】:

  • “一般来说,如果您只对原始字符感兴趣,请使用 istream_iterator”——应该是 istreambuf_iterator
  • 只有一个小细节:iostream 系列本身并没有真正做很多格式化工作——这主要是委托给与流相关的语言环境。 iostream 基本上是一个“媒人”,将语言环境与streambuf 放在一起。不过,大部分实际工作都委托给了其中一个。
  • @Jerry:我不想深入研究语言环境的奇怪之处,因为我自己也不太了解它们,所以我把它留在了那里。
  • @Xeo:尽管我很愿意,但我当然不能怪你!
  • @Jerry:如果您愿意,可以随意将语言环境添加到此答案中,或者自己编写答案。 ;)
【解决方案2】:

这是一个非常保守的秘密:一个 iostream 本身,几乎与从/向您的计算机上的文件进行实际读取或写入无关。

iostream 基本上充当 streambuf 和语言环境之间的“媒人”:

iostream 存储有关应如何进行转换的一些状态(例如,转换的当前宽度和精度)。它使用这些来指导语言环境如何以及在何处进行转换(例如,将此数字转换为该缓冲区中宽度为 8 和精度为 5 的字符串)。

虽然您没有直接询问它,但反过来,语言环境实际上只是一个容器——但(相当奇怪)一个类型安全的异构容器。它包含的东西是facets。一个 facet 对象定义了整个语言环境的一个 facet。该标准定义了从读取和写入数字(num_getnum_put)到分类字符(ctype 方面)的所有方面。

默认情况下,流将使用“C”语言环境。这是非常基本的——数字只是转换为数字流,它识别为字母的唯一内容是 26 个小写和 26 个大写英文字母,依此类推。但是,您可以 imbue 使用您选择的不同区域设置的流。您可以通过字符串中指定的名称选择要使用的语言环境。一个特别有趣的是由一个空字符串选择的。使用空字符串基本上告诉运行时库选择它“认为”最合适的语言环境,通常基于用户如何配置操作系统。这允许代码以本地化格式处理数据,而无需为任何特定语言环境明确编写。

因此,istream_iteratoristreambuf_iterator 之间的基本区别在于,来自 istreambuf_iterator 的数据没有经过(大部分)由语言环境完成的转换,而是来自 @ 987654332@ 已被语言环境转换。

对于它的价值,上一段中的“大部分”是指当您从 istreambuf(通过迭代器或其他方式)读取数据时,一点点基于语言环境的转换 完成:除了各种“格式化”类型的东西外,语言环境还包含一个 codecvt facet,它用于将某些外部表示转换为某些内部表示(例如,UTF-8 到 UTF-32)。

忽略它们都存储在语言环境中这一事实可能更有意义,而只考虑所涉及的各个方面:

这就是istream_iteratoristreambuf_iterator 之间的真正区别。 (至少可能)对来自其中任何一个的数据进行了一点转换,但对来自istreambuf_iterator 的数据进行了大幅较少

【讨论】:

  • 很好的解释。直接对原始二进制数据使用流缓冲区怎么样,这可能吗?
  • @Pavel:这不是 C++ 的 iostream 的工作方式,但至少在理论上,他们没有理由不能这样做。我怀疑你是否愿意——如果你这样做了,你必须一次应用codecvt转换一个字符,因为你从原始缓冲区中读取数据,我相信这通常会失去公平速度量(与一次转换整个缓冲区相比)。
  • 这就是我不想使用 iostreams 的原因,因为我不想涉及到 codecvt。
  • @Pavel:您仍然可以使用 iostreams——您只需要编写自己的流缓冲区来处理下溢(如果是输入流)和/或上溢(如果是输出流),并且读取/写入原始数据,无需进行代码转换。我编写的大多数流缓冲区不进行任何代码转换。
  • @Pavel:除非你做错了什么(例如,使用std::endl,而你只需要\n)iostreams 在速度方面与C I/O 相当有竞争力。 stackoverflow.com/a/1926432/179910
猜你喜欢
  • 2015-01-05
  • 1970-01-01
  • 2016-12-22
  • 1970-01-01
  • 2014-11-18
  • 2021-04-07
  • 2017-07-10
  • 2023-03-12
  • 1970-01-01
相关资源
最近更新 更多