3

I have binary data in a byte sequence described by const unsigned char *p and size_t len. I want to be able to pass this data to a function that expects a std::istream *.

I think I should be able to do this without copying the data, unsafe casts or writing a new stream class. But so far I'm failing. Can anyone help?

Update

Thanks all for the comments. This would seem to be an unanswerable question because std::istream operates with char and conversion would at some point require at least an integer cast from unsigned char.

The pragmatic approach is to do this:

std::string s(reinterpret_cast<const char*>(p), len);
std::istringstream i(s);

and pass &i to the function expecting std::istream *.

paperjam
  • 8,321
  • 12
  • 53
  • 79
  • 2
    Possibly see: http://stackoverflow.com/questions/1448467/initializing-a-c-stdistringstream-from-an-in-memory-buffer – CB Bailey Jul 19 '11 at 13:57
  • Have you actually profiled the code and found that copying the data is the problem? I suspect you'll be better off if you just copy the data and forget about it. – Tom Kerr Jul 19 '11 at 14:14
  • @Tom Performance of copy is not an issue but memory usage of maintaining two copies might be - and in any case, copying needs a cast as I understand it. – paperjam Jul 19 '11 at 14:16
  • 2
    The reason the cast from `unsigned char*` to `char*` is unsafe, is because of the hypothetical existence of non-2's-complement implementations. On 1s' complement or sign-magnitude, `*(signed char*)p != (signed char)*p;`, where `p` is an `unsigned char*` and the referand has the top bit set. If you want to avoid this "unsafe" reinterpretation, you have to perform an unsigned-signed conversion elsewhere. To avoid a copy as well, I think that would mean writing a stream, since AFAIK there isn't anything in the standard libraries that reads from an `unsigned char*`. – Steve Jessop Jul 19 '11 at 15:05
  • Oh, and a further point, the conversion from `unsigned char` to `char` is itself slightly "unsafe" because of those same implementations - if `char` is signed neither one of them can represent `-128` (assuming `CHAR_BIT == 8`), so how is the unsigned value `128` going to be converted to signed? The standard leaves the result of converting values greater than `CHAR_MAX` implementation-defined. – Steve Jessop Jul 19 '11 at 15:11
  • The stream class may want to fiddle with its internal buffer. So you can pass it a const buffer. Unless you write your own. – Martin York Jul 19 '11 at 15:50
  • @paperjam: What about using `std::basic_istringstream i(p);` instead? Does that no work? – wilx Jul 27 '11 at 09:14
  • Answering myself, apparently, it does not work OOTB: http://ideone.com/pKe1o – wilx Jul 27 '11 at 09:18
  • You could avoid the copy using istrstream rather than istringstream - it operates directly on the memory rather than a copy. istrstream is deprecated in the STL but it should still be there. – Pete Aug 03 '11 at 08:26
  • wilx: isn't the `bad_cast` exception in your code caused by the line before your `basic_istringstream`? I don't see why your plan would have to fail? – rubenvb Oct 12 '11 at 09:51

1 Answers1

1

Your answer is still copying.

Have you considered something like this?

const unsigned char *p;
size_t len;

std::istringstream str;
str.rdbuf()->pubsetbuf(
    reinterpret_cast<char*>(const_cast<unsigned char*>(p)), len);
Giovanni Funchal
  • 8,934
  • 13
  • 61
  • 110