I'm writing a subroutine that needs to write data to an existing buffer, and I would like to use the stringstream
class to facilitate the formatting of the data.
Initially, I used the following code to copy the contents of the stream into the buffer, but would like to avoid this solution as it copies too much data.
#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);
}
This is when I discovered the streambuf::pubsetbuf()
method and simply rewrote the above code as follows.
#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;
}
Unfortunately, this does not work under the C++ standard library implementation that ships with Visual Studio 2008; buffer
remains unchanged.
I looked at the implementation of pubsetbuf
and it turns out that it literally "does nothing".
virtual _Myt *__CLR_OR_THIS_CALL setbuf(_Elem *, streamsize)
{ // offer buffer to external agent (do nothing)
return (this);
}
This appears to be a limitation of the given C++ standard library implementation. What is the recommended way to configure a stream to write its contents to a given buffer?
After some more research on this problem, and scrutiny of my code, I came across a post suggesting the use of a hand-coded
std::streambuf
class. The idea behind this code is to create astreambuf
that initializes its internals to refer to the given buffer. The code is as follows.Now if you look at my original code, you will notice that I didn't really need a
stringstream
to begin with. All I really needed was a way to write to an external buffer using the IOStream library andstd::ostream
is a much better type to address this problem. Incidentally, I suspect this is how the array_sink type from Boost.IOStreams is implemented.Here is the modified code that uses my
ostreambuf
type.As the link you posted says: "specific implementations may vary".
Can you not simply return the std::string object and then use std::string::c_str() or std::string::data() at the point the char buffer is required?
Alternatively use sprintf() from the C library, then the whole operation can be completed in the buffer passed. Since that way may result in potential buffer overrun, and you are using Visual C++, you might consider sprintf_s
Looks like a job for the (officially deprecated, but still standard) std::strstream. You could also look at the Boost.IOStreams library, array_sink, in particular.