设置标准流使用的内部缓冲区 (pubsetbuf)
Posted
技术标签:
【中文标题】设置标准流使用的内部缓冲区 (pubsetbuf)【英文标题】:Setting the internal buffer used by a standard stream (pubsetbuf) 【发布时间】:2010-12-02 10:12:16 【问题描述】:我正在编写一个需要将数据写入现有缓冲区的子程序,我想使用stringstream
类来方便数据的格式化。
最初,我使用以下代码将流的内容复制到缓冲区中,但想避免这种解决方案,因为它复制了太多数据。
#include <sstream>
#include <algorithm>
void FillBuffer(char* buffer, unsigned int size)
std::stringstream message;
message << "Hello" << std::endl;
message << "World!" << std::endl;
std::string messageText(message.str());
std::copy(messageText.begin(), messageText.end(), buffer);
这是我发现streambuf::pubsetbuf()
方法的时候,简单地将上面的代码改写如下。
#include <sstream>
void FillBuffer(char* buffer, unsigned int size)
std::stringstream message;
message.rdbuf()->pubsetbuf(buffer, size);
message << "Hello" << std::endl;
message << "World!" << std::endl;
不幸的是,这在 Visual Studio 2008 附带的 C++ 标准库实现下不起作用; buffer
保持不变。
我查看了pubsetbuf
的实现,结果发现它实际上“什么都不做”。
virtual _Myt *__CLR_OR_THIS_CALL setbuf(_Elem *, streamsize)
// offer buffer to external agent (do nothing)
return (this);
这似乎是给定 C++ 标准库实现的限制。配置流以将其内容写入给定缓冲区的推荐方法是什么?
【问题讨论】:
@Steve 我也在用VS2008,但是已经实现了! @Arak -- 我的pubsetbuf()
实现转发到私有setbuf()
操作,如上实现。您能否确认您的实施有所不同?
这在 VS2010 中仍然适用
在 VS2017 中仍然如此
【参考方案1】:
在对这个问题进行更多研究并仔细检查我的代码后,我发现a post 建议使用手动编码的std::streambuf
类。这段代码背后的想法是创建一个streambuf
,它初始化其内部以引用给定的缓冲区。代码如下。
#include <streambuf>
template <typename char_type>
struct ostreambuf : public std::basic_streambuf<char_type, std::char_traits<char_type> >
ostreambuf(char_type* buffer, std::streamsize bufferLength)
// set the "put" pointer the start of the buffer and record it's length.
setp(buffer, buffer + bufferLength);
;
现在,如果您查看my original code,您会注意到我并不真正需要stringstream
。我真正需要的只是一种使用iostream 库写入外部缓冲区的方法,而std::ostream
是解决此问题的更好类型。顺便说一句,我怀疑这就是 Boost.IOStreams 中的 array_sink 类型的实现方式。
这是使用我的ostreambuf
类型的修改代码。
#include <ostream>
#include "ostreambuf.h" // file including ostreambuf struct from above.
void FillBuffer(char* buffer, unsigned int size)
ostreambuf<char> ostreamBuffer(buffer, size);
std::ostream messageStream(&ostreamBuffer);
messageStream << "Hello" << std::endl;
messageStream << "World!" << std::endl;
【讨论】:
这段代码是否没有 null 终止缓冲区的问题?考虑到这是一个 hello world 示例,我猜缓冲区应该是空终止的。【参考方案2】:看起来像是(正式弃用,但仍然是标准的)std::strstream 的工作。您还可以查看Boost.IOStreams 库,尤其是array_sink。
【讨论】:
std::strstream 不就是 std::stringstream 的同义词吗?为什么会有不同的实施方式? 不,因为它允许用户直接提供和管理缓冲区,所以效率更高(使用起来也很棘手)。例如,请参阅gotw.ca/publications/mill19.htm 中的选项 #4。 @Clifford: kera.name/articles/2008/09/…【参考方案3】:正如您发布的链接所说:“具体实现可能会有所不同”。
你不能简单地返回 std::string 对象,然后在需要 char 缓冲区的地方使用 std::string::c_str() 或 std::string::data() 吗?
或者使用 C 库中的 sprintf(),那么整个操作可以在传递的缓冲区中完成。由于这种方式可能会导致潜在的缓冲区溢出,并且您使用的是 Visual C++,因此您可以考虑sprintf_s
【讨论】:
不幸的是,我不能使用c_str()
,因为缓冲区属于另一种类型。我希望用一些东西填充该缓冲区,以便其他类型可以对其进行操作。 sprintf_s()
会很好用,我使用它应该没有问题。以上是关于设置标准流使用的内部缓冲区 (pubsetbuf)的主要内容,如果未能解决你的问题,请参考以下文章