|
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