From: Aurélien on
Hello,

Some days ago, I decided that it would be fun to write a `streambuf`
subclass that would use `mmap` and read-ahead.
I looked at how my STL (SGI) implemented `filebuf` and realized that
`basic_filebuf` contains a `FILE*`. So inheriting from `basic_filebuf`
is out of the question.

So I inherited from `basic_streambuf`. Then i wanted to bind my
`mmapbuf` to a fstream.

I thought the only thing that I would have to do would be to copy the
implicit interface of `filebuf`... but that was a clear mistake. In
the SGI, basic_fstream owns a `basic_filebuf`. No matter if I call
`basic_filestream.std::::ios::rdbuf( streambuf* )`, the filestream
completely ignores it and uses its own `filebuf`.

So now I'm a bit confused... sure, I can create my own `mmfstream`,
that would be the exact copy/paste of the `fstream` but that sounds
really no DRY-oriented.

What I can't understand, is: **why does `fstream` is so tightly
coupled with `filebuf`, so that it is not possible to use anything
else than a `filebuf`?** The whole point of separating streams and
bufs is that one can use a stream with a different buffer.

Solutions:

=> `filestream` should rely on the implicit interface of `filebuf`.
That is, fstream should be templated by a streambuf class. That would
allow everyone to provide its own streambuf subclass to a `fstream` as
long as it implements `filebuf`'s implicit interface. Problem: we
cannot add a template parameter to `fstream` since it would break
template selectors while using `fstream` as template template
parameter.

=> `filebuf` should be a pure virtual class without any additional
attributes. So that one can inherit from it without carrying all its
FILE* garbage.

Your ideas on the subject ?

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Ulrich Eckhardt on
Aurélien wrote:
> Some days ago, I decided that it would be fun to write a `streambuf`
> subclass that would use `mmap` and read-ahead.

Others thought so, too, at least e.g. STLport does this and I guess also any
other implementation of rank and name. BTW: Even using a FILE* you can
already use memory mapping!

> I looked at how my STL (SGI) implemented `filebuf` and realized that
> `basic_filebuf` contains a `FILE*`. So inheriting from `basic_filebuf`
> is out of the question.
>
> So I inherited from `basic_streambuf`. Then i wanted to bind my
> `mmapbuf` to a fstream.

I wouldn't do that, because an fstream already includes a filebuf which
would then be unused. Of course, you can redirect the fstream to a
different filebuf, but that would be kind of useless. Instead, use a simple
iostream which you pass a pointer to the streambuf in its constructor. Or,
you create a class mmapfstream, publicly derived from iostream and
containing an mmapfilebuf, which then gives the streambuf to the baseclass
using rdbuf()[1]. You then forward calls to open/close to the streambuffer,
just like fstream does.

> I thought the only thing that I would have to do would be to copy the
> implicit interface of `filebuf`... but that was a clear mistake. In
> the SGI, basic_fstream owns a `basic_filebuf`. No matter if I call
> `basic_filestream.std::::ios::rdbuf( streambuf* )`, the filestream
> completely ignores it and uses its own `filebuf`.

That would be a bug in the implementation, if I understand you correctly,
which in turn I'm not 100% sure I do. Show some code and I'll be able to
tell you.

> So now I'm a bit confused... sure, I can create my own `mmfstream`,
> that would be the exact copy/paste of the `fstream` but that sounds
> really no DRY-oriented.

True, but I'm afraid that's the way to go.

> What I can't understand, is: **why does `fstream` is so tightly
> coupled with `filebuf`, so that it is not possible to use anything
> else than a `filebuf`?** The whole point of separating streams and
> bufs is that one can use a stream with a different buffer.

Actually, it never hurt me in practice. The code that makes up fstream,
ifstream and ofstream is so little that it actually doesn't hurt repeating
it when you create your own versions thereof, most of the actual code is in
the streambuffer.

Cheers!

Uli


[1] You can't pass the streambuffer to the baseclass because the
streambuffer's constructor has not been called at that time, hence you must
switch it later (e.g. in the constructor's body) using rdbuf()!

Sator Laser GmbH
Geschäftsführer: Thorsten Föcking, Amtsgericht Hamburg HR B62 932


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]