【问题标题】:Create std::stringbuf based on std::vector<char>基于 std::vector<char> 创建 std::stringbuf
【发布时间】:2012-03-26 08:44:31
【问题描述】:

我正在两个框架(OpenSceneGraph 和 wxWidgets)之间进行内存中的图像转换。不想关心底层类(osg::ImagewxImage),我使用两个 API 提供的面向流的 I/O 功能,如下所示:

1) 创建std::stringstream

2) 使用 OSG 的 writer 写入流

3) 使用 wxWigdets 阅读器从流中读取

这很好用。到目前为止,我一直在使用对流缓冲区的直接访问,但最近我的注意力被std::stringstream 的“非连续底层缓冲区”问题所吸引。我一直在使用 kludge 将 const char* ptr 放入缓冲区 - 但它有效(在 Windows、Linux 和 OSX 上测试,使用 MSVC 9 和 GCC 4.x),所以我从未修复它。

现在我明白这段代码是一个定时炸弹,我想摆脱它。这个问题已经在 SO (here for instance) 上多次提出,但我找不到真正能帮助我做最简单的事情的答案。

我认为最合理的做法是在幕后使用向量创建我自己的 streambuf - 这将保证缓冲区是连续的。我知道这不是一个通用的解决方案,但考虑到我的限制:

1) 所需的大小不是无限的,实际上是可以预测的

2) 由于 API,我的流确实需要是 std::iostream(我不能使用原始字符数组)

任何人都知道我如何使用 chars 向量来自定义 stringbuf 吗?请不要回答“使用std::stringstream::str()”,因为我知道我们可以,但我正在寻找其他东西(即使你会说复制 2-3 MB 如此之快以至于我什至不会注意到差异,让我们考虑一下,我仍然对自定义 stringbuf 感兴趣,只是为了练习的美感)。

【问题讨论】:

    标签: c++ iostream


    【解决方案1】:

    如果您只能使用 istreamostream(而不是 双向),不需要寻找,很简单(大约10 代码行)使用std::vector&lt;char&gt; 创建您自己的streambuf。 但是除非字符串非常非常大,否则为什么要麻烦呢? C++11 标准 保证std::string 是连续的;那个char*&amp;myString[0] 获得的可以用作 C 风格的数组。 C++11 添加此保证的原因是承认现有的 实践;根本没有任何实现,这不是 案例(现在它是必需的,不会有任何实现 不是这种情况的未来)。

    【讨论】:

    • 我不确定我是否理解您的回答。关于仅使用 istream/ostream:一个插件需要查看 ostream,而另一个插件需要查看 istream。也许我可以使用相同的基础向量构建每个?关于使用 std::string:好的,但是如何从字符串中创建流?
    • @如果一个插件需要 ostream,另一个需要 istream,那么你可能需要做一些双向的。或者,如果他们不需要同时使用它们,那么首先创建一个 ostream,然后是 istream,使用相同的缓冲区。至于字符串中的流:std::[io]stringstream 已经存在。
    • 你的意思是std::stringstream的缓冲区,根据C++11,保证是连续的吗?而且我在任何地方都读不到 std::stringstreams 在内部使用了 std::strings - 任何指针?
    • 所有streambuf的缓冲区都保证是连续的。否则,界面无法工作。但这不是问题;你不关心缓冲区的样子,因为除非你是从streambuf 派生的,否则你看不到它。
    【解决方案2】:

    boost::iostreams 为此提供了一些现成的接收器。 array_sink 如果你有某种上限并且可以预先分配块,这样的接收器不会动态增长,但另一方面也可以是积极的。还有back_inserter_device,它更通用,例如可以直接与std::vector 一起使用。使用 back_inserter_device 的示例:

    #include <string>
    #include <iostream>
    #include "boost/iostreams/stream_buffer.hpp"
    #include "boost/iostreams/device/back_inserter.hpp"
    int main() 
    {
        std::string destination;
        destination.reserve( 1024 ); 
        boost::iostreams::stream_buffer< boost::iostreams::back_insert_device< std::string > > outBuff( ( destination ) );
        std::streambuf* cur = std::cout.rdbuf( &outBuff );
        std::cout << "Hello!" << std::endl;
        // If we used array_sink we'd need to use tellp here to retrieve how much we've actually written, and don't forgot to flush if you don't end with an endl!
        std::cout.rdbuf( cur );
        std::cout << destination;
    }
    

    【讨论】:

    • 谢谢。我没有在这个项目中使用 boost,但会将你的解决方案放在我的枕头下,以备将来使用。
    猜你喜欢
    • 2012-03-07
    • 1970-01-01
    • 2011-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-11
    相关资源
    最近更新 更多