I have a network client with a request method that takes a std::streambuf*
. This method is implemented by boost::iostreams::copy
-ing it to a custom std::streambuf
-derived class that knows how to write the data to a network API, which works great. This means I can stream a file into the request without any need to read it all into memory.
There are some cases, however, where large blocks of data must be sent which are not in a file, so I included an overload that takes a string. To avoid duplicating all the network code in the stream, it seemed obvious that I should set up a streambuf
representing the string and call the other method. The only way I could figure out to make this work was something like:
std::istringstream ss(data);
send(ss.rdbuf());
Unfortunately, istringstream
makes a copy of the data, which in some cases is several megabytes. It makes perfect sense in the general case, of course, if you hand a const reference to some object you don't want that object assuming it can continue using that reference.
I worked around this with the following:
struct zerocopy_istringbuf
: public std::stringbuf
{
zerocopy_istringbuf(std::string const* s)
: std::stringbuf(std::ios::in)
{
char* p = const_cast<char*>(s->c_str());
setg(p, p, p + s->length());
}
};
...
send(&zerocopy_istringbuf(data));
This seems to work just fine, but I wonder if it's really necessary. Why doesn't std::istringstream
have an overload taking a std::string const *
? Is there a better way to do this?