Setting the internal buffer used by a standard stream (pubsetbuf)

c++, stream, visual-c++

Solution

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 a `streambuf` that initializes its internals to refer to the given buffer. The code is as follows.

#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);
    }
};

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 and `std::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.

#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;
}

For a more complex example see:

- What's wrong with this stream buffer?

Problem

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?

Original source

Related problems