【问题标题】:Block-level copying of data between streambuffers流缓冲区之间的数据块级复制
【发布时间】:2016-09-01 17:56:55
【问题描述】:

我想在std::streambuf 实例之间高效地复制数据。也就是说,我想在它们之间铲起数据块,而不是执行逐个字符的复制。例如,这不是我要找的:

stringbuf in{ios_base::in};
stringbuf out{ios_base::out};
copy(istreambuf_iterator<char>{in},
     istreambuf_iterator<char>{},
     ostreambuf_iterator<char>{out});

这里有语法糖,有更多的错误检查:

ostream os{&out};
os << &in;

这是我的标准库(Mac OS X,XCode 7)中operator&lt;&lt;(basic_streambuf&lt;..&gt;*) 的实现的sn-p:

                typedef istreambuf_iterator<_CharT, _Traits> _Ip;
                typedef ostreambuf_iterator<_CharT, _Traits> _Op;
                _Ip __i(__sb);
                _Ip __eof;
                _Op __o(*this);
                size_t __c = 0;
                for (; __i != __eof; ++__i, ++__o, ++__c)
                {
                    *__o = *__i;
                    if (__o.failed())
                        break;
                }

底线是:这仍然是按字符复制。我希望标准库使用一种算法,该算法依赖于流缓冲区的块级成员函数sputnsgetn,而不是按字符传输。标准库是否提供这样的算法,还是我必须自己推出?

【问题讨论】:

  • 问题是这是基于一个带有虚函数的接口。您永远不知道*__o = *__i 何时无法输出,因此您无法提前阅读并冒丢失这些字符的风险。
  • 找到方法了吗?

标签: c++ iostream streambuf


【解决方案1】:

恐怕答案是:以标准库的当前设计是不可能的。原因是流缓冲区完全隐藏了它们管理的字符序列。这使得无法直接将字节从一个流缓冲区的 get 区域复制到另一个流缓冲区的 put 区域。

如果“输入”流缓冲区会暴露其内部缓冲区,那么“输出”流缓冲区可以只使用sputn(in.data(), in.size())。或者更明显的是:如果输出缓冲区也暴露了它的内部缓冲区,那么可以使用普通的memcpy 在两者之间铲除字节。其他 I/O 库以这种方式运行:例如,Google 协议缓冲区的 stream implementation。 Boost IOStreams 有一个optimized implementation to copy between streams。在这两种情况下,高效的块级复制都是可能的,因为流缓冲区等效项提供了对其中间缓冲区的访问。

事实上,具有讽刺意味的是,流缓冲区甚至不需要缓冲区:当无缓冲操作时,每次读/写都直接进入底层设备。大概这是标准库不支持自省的原因之一。不幸的结果是输入和输出流缓冲区之间的有效复制是不可能的。块级复制需要一个中间缓冲区,复制算法的操作如下:

  1. 通过sgetn 从输入流缓冲区读取到中间缓冲区。
  2. 通过sputn从中间缓冲区写入输出流缓冲区。
  3. 转到 1。直到输入耗尽或写入输出流缓冲区失败

【讨论】:

    猜你喜欢
    • 2012-03-09
    • 2019-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-10
    • 1970-01-01
    • 1970-01-01
    • 2014-01-09
    相关资源
    最近更新 更多