initializing a C++ std::istringstream from an in memory buffer?
Asked Answered
C

4

16

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?

Charpoy answered 19/9, 2009 at 12:28 Comment(1)
Possible duplicate of Setting the internal buffer used by a standard stream (pubsetbuf)Task
T
9

Look at std::istrstream it has a constructor

 istrstream( char* pch, int nLength );

This class is sort of depreciated or at least you are normally told to use other classes.
The issue with strstream is that it is more complex to manage the memory of the char* buffer so in general you would prefer stringstream as it does the memory management for you. However in this case you are already managing the memory of the char* so the normal benefit is in this case a cost. In fact in this case strstream does exactly what you want with minimal overhead in code or speed. This is similar to the discussion of ostrsteram by Herb Sutter

Thomajan answered 19/9, 2009 at 12:39 Comment(2)
Yeah, but Josuttis says "The char* stream classes are retained only for backward compatibility. Their interface is error prone and they are rarely used correctly." This is why I was a bit reluctant to use them. And "retained only for backward compatibility" seems to imply there is a better way using "better" classes.Charpoy
I read that article, it's directly relevant. thanks. I guess my question is answered, though no comment on the "tmp_blob.rdbuf()->pubsetbuf(blockPtr, blockLength);" approach.Charpoy
B
49

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();
}
Bottommost answered 19/9, 2009 at 21:8 Comment(1)
Haha, your solution didn't come up in search results when I posted my question. We've got pretty much the same thing ;) #2080412Plumlee
T
9

Look at std::istrstream it has a constructor

 istrstream( char* pch, int nLength );

This class is sort of depreciated or at least you are normally told to use other classes.
The issue with strstream is that it is more complex to manage the memory of the char* buffer so in general you would prefer stringstream as it does the memory management for you. However in this case you are already managing the memory of the char* so the normal benefit is in this case a cost. In fact in this case strstream does exactly what you want with minimal overhead in code or speed. This is similar to the discussion of ostrsteram by Herb Sutter

Thomajan answered 19/9, 2009 at 12:39 Comment(2)
Yeah, but Josuttis says "The char* stream classes are retained only for backward compatibility. Their interface is error prone and they are rarely used correctly." This is why I was a bit reluctant to use them. And "retained only for backward compatibility" seems to imply there is a better way using "better" classes.Charpoy
I read that article, it's directly relevant. thanks. I guess my question is answered, though no comment on the "tmp_blob.rdbuf()->pubsetbuf(blockPtr, blockLength);" approach.Charpoy
J
5

Boost.IOStreams has a stream that works like a stringstream, but wraps a native array, so you avoid having to copy the data.

std::stringstream always creates its own internal buffer

Joyous answered 19/9, 2009 at 12:47 Comment(0)
S
-1

Untested but perhaps worth a test...

std::stringstream ss;
ss.write( blockPtr, blockLength );
ss.seekg(0);

Then call that setBlob function with ss. Your still have that internal buffer in std::stringstream as jalf already mentioned though.

Spirochete answered 19/9, 2009 at 18:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.