我在两个框架(OpenSceneGraph和wxWidgets)之间进行内存中图像转换。我不想关心底层类(osg::Image
和wxImage
),我使用了这两种API提供的面向流的I / O特性:
1)创建std::stringstream
2)使用OSG的作者写入流
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
(我不能使用原始字符数组)
任何人都知道如何使用字符向量自定义stringbuf?请不要回答“使用std::stringstream::str()
”,因为我知道我们可以,但我正在寻找别的东西(即使你说复制2-3 MB是这样的很快,我甚至都没有注意到差异,让我们考虑一下我仍然对定制的字符串组件感兴趣,只是为了练习的美感。)
答案 0 :(得分:3)
如果您只能使用istream
或ostream
(而不是
双向),不需要寻求,这很简单(约10
代码行)使用streambuf
创建您自己的std::vector<char>
。
但除非字符串非常非常大,为什么要费心呢? C ++ 11标准
保证std::string
是连续的;那个char*
由&myString[0]
获得的可以用作C风格的数组。而且
原因C ++ 11补充说这个保证是为了表彰现有的
实践;根本没有任何实现,这不是
case(现在它是必需的,将不会有任何实现)
未来的情况并非如此)。
答案 1 :(得分:1)
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;
}