How reliable are basic_stringbuf::in_avail() and basic_stringbuf::str()?
I need to get all the contents from a stream, without actually extracting them (just like 开发者_如何学Gostringstream::str()
). I've tried basic_stringbuf::str()
, but it behaves incorrectly when the stream is empty. To avoid that case, I had a go at basic_stringbuf::in_avail()
, but that hasn't worked out very well either.
In the following test case, in_avail()
doesn't return the number of available elements on the stream, and str()
returns more elements than what is currently there:
#include <iostream>
#include <iterator>
#include <vector>
#include <sstream>
// extracts everything from the stream
std::vector<unsigned char> stream2vector(std::basic_istream<unsigned char>& stream)
{
std::vector<unsigned char> retreivedData;
std::istreambuf_iterator<unsigned char> it(stream);
const std::istreambuf_iterator<unsigned char> endOfStream;
retreivedData.insert(retreivedData.begin(), it, endOfStream);
return retreivedData;
}
int main() {
std::basic_stringbuf<unsigned char> buf;
std::basic_iostream<unsigned char> stream(&buf);
unsigned char array[5] = { 1, 2, 3, 4, 5 };
stream.write(array, 5);
std::cout << "rdbuf()->in_avail(): " << buf.in_avail() << "\n";
std::vector<unsigned char> d1 = stream2vector(stream);
std::cout << "d1.size(): " << d1.size() << "\n";
std::cout << "\n";
// d2 should be empty
std::vector<unsigned char> d2 = stream2vector(stream);
std::cout << "d2.size(): " << d2.size() << "\n";
std::basic_string<unsigned char> s = buf.str();
std::cout << "buf.str().size(): " << buf.str().size() << "\n";
}
Compiling on g++ 4.4, the output is:
rdbuf()->in_avail(): 1 // expected: 5
d1.size(): 5 // as expected
d2.size(): 0 // as expected
buf.str().size(): 5 // expected: 0
What am I doing wrong? What's the best way to do what I'm trying?
Thanks a lot.
in_avail
is the number of characters ready to be read from the buffer, not the size of the buffer itself. It's really allowed to return any nonzero value here.
However, I can't answer what the best way is of what you're doing, because I don't know what you're doing. If you already have things as an unsigned char
array, then you're going to want to do:
std::vector<unsigned char> data(array, array + sizeof(array)/sizeof(unsigned char));
If you're just trying to read a whole stream into a vector, then I would do exactly what you're doing; I'd just replace you're stream2vector function with this, equivalent, simpler one:
// extracts everything from the stream
std::vector<unsigned char> stream2vector(std::basic_istream<unsigned char>& stream)
{
std::istreambuf_iterator<unsigned char> it(stream);
const std::istreambuf_iterator<unsigned char> endOfStream;
return std::vector<unsigned char>(it, endOfStream);
}
I'm not entirely sure why you're specializing every operation here for unsigned char
-- I would just use the default char
versions, because unsigned char
is allowed to be the same size as a short
, which is probably not what you want (but I am not aware of any implementation that does this).
精彩评论