我正在编写一个需要将数据写入现有缓冲区的子程序,我想使用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 ++标准库实现的限制。配置流以将其内容写入给定缓冲区的推荐方法是什么?
答案 0 :(得分:19)
经过对此问题的更多研究以及对我的代码的详细审查后,我发现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
是解决此问题的更好的类型。顺便说一句,我怀疑这是array_sink Boost.IOStreams类型的实现方式。
以下是使用我的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;
}
答案 1 :(得分:4)
看起来像(正式弃用,但仍然是标准的)std::strstream的工作。您还可以查看Boost.IOStreams库,特别是array_sink。
答案 2 :(得分:1)
正如您发布的链接所说:“具体实施可能会有所不同”。
你能不能简单地返回std :: string对象,然后在需要char缓冲区时使用std :: string :: c_str()或std :: string :: data()?
或者从C库中使用sprintf(),然后可以在传递的缓冲区中完成整个操作。由于这种方式可能导致潜在的缓冲区溢出,并且您使用的是Visual C ++,您可能会考虑sprintf_s