Boost logo

Boost :

Subject: Re: [boost] Interest in simple unformatted binary stream I/O?
From: Max Sobolev (macsmr_at_[hidden])
Date: 2011-04-29 07:13:41


On 29.04.2011 11:52, Mathias Gaunard wrote:
>> int main()
>> {
>> fstream f("binary_stream_example.dat",
>> std::ios_base::trunc | std::ios_base::in | std::ios_base::out |
>> std::ios_base::binary);
>>
>> int32_t x = 0x01020304;
>> int32_t y = 0;
>>
>> f<< bin(x); // write 4 bytes
>> f.seekg(0);
>> f>> bin(y); // read 4 bytes
>
> I think it's a bad idea.
>
> If you want to do that kind of thing, you should use the streambuf
> abstraction directly, along with its sgetn and sputn member functions.
> It will be much more efficient.

I am not agree.
(If you *want* to use the streambuf directly, you should :) But don't
force everyone to use this low-level tool.)

I think binary stream IO shouldn't be implemented on the
manipulator-like basis, an independent raw_stream class with minimal and
full functionality is better.
Then below I don't tied to proposed syntax (on the manipulator-like basis).

A stream provide automatic "type deduction" / type safety, therefore an
user shouldn't specify the type by hand:

double d;
char c;
raw_stream raw;
raw << d << c;
raw >> d >> c;

but with streambuf it should:

std::streambuf* buf = . . . ;
double d = . . . ;
buf->sputn(reinterpret_cast<char const*>(&d), sizeof( double ));
int i = . . . ;
buf->sputn(reinterpret_cast<char const*>(&i), sizeof( int ));

It's error-prone; and the user to simplify its job should write template
wrapper like:

template<typename T> void put(std::streambuf* buf, T value)
{
   buf->sputn(reinterpret_cast<char const*>(&value), sizeof( T ));
}

template<typename T> T get(std::streambuf* buf)
{
   T value;
   buf->sgetn(reinterpret_cast<char*>(&value), sizeof( T ));
   return value;
}

..but a similar "type deduced" / type-safe code already written for
stream (in more convenient manner) and placed in library for general use.

sgetn() / sputn() functions doesn't support endianess directly, the user
should use something like reverse_iterator<char*> explicitly.

In stream's environment endianess can be implemented on the manipulator
basis:

raw_stream raw;
raw << ordering::little_endian << 1.0 << 'X' << 127;
double d;
char c;
int i;
raw >> d >> c >> ordering::big_endian >> i;
std::cout << d << " - " << c << " - "
           << std::hex << std::showbase << i << std::endl;
// out: 1 - X - 0x7f000000
// on a little-endian machine

Streams are highly extensible with a well-known to every C++ programmer
interface; library can provide shift operators overloaded for
std::vector<>, std::basic_string<>, std::deque<> and std::list<> in a
separate library's header:

std::vector<int> v;
raw << v; // trivial implementation
raw >> v;
raw << some_user_type(); // if operator << (raw_stream&, some_user_type)
exists and found via ADL

With streambuf it's not so convenient.

-- 
- thank you for your indulgence about my poor english :)

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk