Why doesn't std::istream assume ownership over its streambuf?
Asked Answered
E

1

6

I am writing some sort of virtual file system library for video-games in the likes of CRI Middleware's ROFS (see Wikipedia). My intention with the library is to provide natural means of accessing the resources of the games I develop, which store some data embedded in the executable, some on the media and some on the local user's hard drive (preferences, save game files, etc).

Access to such resources should be as simple as making a call like

std::auto_ptr<std::istream> defaultConfigIStream(
    fslib.inputStream("self://defaultConfig.ini"));
std::auto_ptr<std::ostream> defaultConfigOStream(
    fslib.outputStream("localappdata://config.ini"));

// Copies default configuration to local user's appdata folder
defaultConfigIStream >> defaultConfigOStream;

The actual way of doing things is actually different, with another abstraction layer used for background loading, but that's not important here.

What I want to know is how can I return that auto_ptr<> (or unique_ptr<>, you choose) considering that the std::streambuf<> associated with the std::[i/o]stream<> is not deleted by it when it's destroyed.

I am considering std::[i/o]stream<> doesn't assume ownership over the streambuf passed to it upon construction as the constructor doesn't present transfer of ownership semantics and Apache's STDCXX reference doesn't mention transer of ownership (nor do any of the stdlib references I've found on the internet).

What alternatives do I have? I might as well return a shared pointer and keep watching it until the FSlib manager keep a unique copy of the shared pointer, in which case it would destroy its unique copy as well as the streambuf. That's practical, considering the library's organizational model, but this isn't very elegant nor efficient for that matter.

I've tried taking a look at Boost.Iostreams, but it seems things are even worse with it for me, as streams themselves have their Device types strongly attached to their type (the Device for a stream has to be defined in its template parameter). This problem seems to make the use of Boost.Iostreams unfeasible for my library, as it needs to abstract away the concrete "source/sink" implementation of the streams so that streams can be used seamlessly to open a file located inside the executable itself, inside a file from the system's file system or inside an archive-type file, for example.

I could write a container class that handles these issues, but I'd rather do it more cleanly (i.e. just return the stream already; that's all it should need! ;).

Suggestions?

Eximious answered 17/1, 2010 at 23:53 Comment(0)
I
8

You could just derive your own stream classes from istreamresp. ostream, set the buffer in the constructor and destroy it in the destructor.

Something like:

class config_istream : public std::istream {
public:
    config_istream(std::string name) : 
      std::istream(fslib.InputStream(name.c_str())) 
    {
    }

    ~config_istream() { delete rdbuf(); }
};

Have a look on how the fstream classes are implemented, they deal with a similar problem (filebuf has to be deleted together with fstream)

Interdiction answered 18/1, 2010 at 0:13 Comment(1)
Yeah, as I said by the end of the question, I think I'll have to do that. I just wanted to know if there was some easier way to do it XD ThanksCally

© 2022 - 2024 — McMap. All rights reserved.