I have a memory block (opaque), that I want to store in a Blob in mySQL through their C++ adapter. The adapter expects a istream:
virtual void setBlob(unsigned int parameterIndex, std::istream * blob) = 0;
So my question is: how can I create a std::istream from this memory block (typed as char*). It's not a string as it is not null-terminated (but I know its length of course).
I could not find a way to do it without copying my memory block for example in a std::string. I think this is a bit wasteful. Something like this doesn't work:
std::streambuf istringbuf(blockPtr, blockLength);
std::istringstream tmp_blob(&istringbuf);
because std::streambuf doesnt have such a constructor. I saw the following suggestion.
std:: istringstream tmp_blob;
tmp_blob.rdbuf()->pubsetbuf(blockPtr, blockLength);
Is that the correct way?
It's actually pretty trivial to write a one-shot std::streambuf
that uses the buffer in place as the default behaviour of all the virtual functions of std::streambuf
does 'the right thing'. You can just setg
the read area in construction and underflow
and uflow
can safely be left to return traits_type::eof()
as the end of the initial get area is the end of the stream.
e.g.:
#include <streambuf>
#include <iostream>
#include <istream>
#include <ostream>
struct OneShotReadBuf : public std::streambuf
{
OneShotReadBuf(char* s, std::size_t n)
{
setg(s, s, s + n);
}
};
char hw[] = "Hello, World!\n";
int main()
{
// In this case disregard the null terminator
OneShotReadBuf osrb(hw, sizeof hw - 1);
std::istream istr(&osrb);
istr >> std::cout.rdbuf();
}