views:

227

answers:

4

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 not 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 ?

+1  A: 

fstream in itself is not a big class. It inherits from basic_stream to provide support for all the << and >> operations, contains a specialized steambuf that have to be initialized, and the corresponding constructors to pass the parameters to the streambuf constructor.

In a sense, what you wrote about your templated solution is OK. But basic_stream can also be derived into a tcp_stream for example. In that case, the constructors of fstream are a bit useless. Thus you need to provide a new tcpstream class, inheriting from basic_stream with the correct parameters for the constructors to be able to create the tcp_stream. In the end, you wouldn't use anything from fstream. Creating this new tcpstream is a matter of writing 3 or 4 functions only.

In the end, you would derive from the fstream class without any real reason to. This would add more coupling in the class hierarchy, unneeded coupling.

Didier Trosset
I totally agree with the tcp_stream thing, since a tcp stream cannot be manipulated like a file stream nor a string stream. But here, we are speaking of two streambuffers that should be accessed in the exact same way: they both manipulate files, and should both be accessed by filestream. What is the point of having fstream and a filebuf in different classes if you can't use one without the other ?
Aurélien Vallée
I am pretty sure that you will need to provide additional parameters (more than the ones given to `filebuf`) to your new `streambuf`. Thus, you will have to write new constructors for your new `filestream`. These constructors are the only thing you'll have to write, to create it, be it by deriving, or being standalone.
Didier Trosset
@Didier Trosset> No, i'll have to implement all the fstream additional features: open, close, is_open, ... And, the problem is not writing these little methods, it's just I shouldn't have to do it. This will be a copy/paste, no code reuse. More importantly, my users will have to switch from fstream to mmfstream, that should not be.
Aurélien Vallée
Because you could use the other without the one!
Didier Trosset
@sbi: fair point, didn't read it that way. Comment and downvote deleted.
MSalters
A: 

The whole point of std::fstream is that it is a _F_ile based std::stream. If you want an ordinary std::stream backed by your mmstreambuf, then you should create a mmstreambuf and pass it to std::stream::stream(std::streambuf*)

MSalters
"The whole point of std::fstream is that it is a _F_ile based std::stream" > And I **want** a file based stream! My `mmstreambuf` class provides the exact same features of a `filebuf`, but using mapped memory instead of buffered memory.
Aurélien Vallée
+2  A: 
sbi
I'd be __very__ interested to learn why this was down-voted.
sbi
Because you did not answered the question. Nothing written here helps in any way to solve the problem. That is like you are speaking to yourself, answering an imaginary "what is the difference between iostream and streambuf" question...
Aurélien Vallée
@Aurélien: Fair point, except that I certainly _meant_ to answer your question. I have tried to change the answer so that this becomes more obvious.
sbi
Fair, I cancelled the downvote. Thanks for your time :)
Aurélien Vallée
@Aurélien: Thanks for doing that.
sbi
+3  A: 

Check out mapped_file in the Boost.Iostreams library. I've never used used it myself, but it seems like it might already do what you need.

EDIT: Oops, reread your questions and I see you're doing this for fun. Perhaps you can draw inspiration from Boost.Iostreams?

Emile Cormier
Yeah I chatted with a colleague this morning and he informed me too that boost already have it :) But as you noticed, that's mainly for fun! Thanks.
Aurélien Vallée