Reputation: 6933
So I have some code that reads from text files, and some of the files are gzipped. I thought I could be clever by having a function that produces basic_istreams and the users of the streams not know or care about how the data is being processed. So I wrote:
basic_istream<char>* openFile(const string& filename);
...and the parsing class calls the function and doesn't know about what's going on under the covers. The problem is with cleanup. When what I'm actually doing is just opening an fstream
, I can just delete the stream and I'm all set. But with a filtering_stream
it gets more complicated. Here's what sample code creating a filtering_stream to read gzipped files looks like:
std::ifstream file (filename, std::ios_base::in | std::ios_base::binary);
boost::iostreams::filtering_istream in;
in.push (boost::iostreams::gzip_decompressor());
in.push (file);
...but obviously in my case I can't create these objects on the stack because I need them to outlive the function call and they're not copy-constructible. So I have to allocate a new ifstream and a new filtering_istream, and the caller only sees the filtering_istream and has no way to delete the ifstream (which the filtering_istream doesn't delete for you.)
What is the best way to deal with this? I can think of lots of clumsy solutions -- return both a basic_istream*
and a list of basic_istream*
s to destroy; return an object that essentially acts like a cleanup() closure; etc. -- but I can't think of anything I'm really happy with. Thanks in advance for any guidance you can offer.
Upvotes: 0
Views: 1018
Reputation: 96241
What about returning a shared_ptr
(std or boost) instead of a raw pointer. Then you can set the deleter to a function object that know hows to delete ALL the respective components.
For example:
basic_istream<char>* openFile(const string& filename)
{
if(normal_file)
{
return boost::shared_ptr<basic_istream<char> >(however_you_create_stream);
}
else
{
// GZIPed file.
return boost::shared_ptr<basic_istream<char> >(filtering_stream, CleanupStreams(filtering_stream_ptr, raw_stream_ptr));
}
}
Upvotes: 2
Reputation: 4258
Maybe you could subclass boost::iostreams::filtering_istream
and add somthing like a push_cleanup
member function, that would take a pointer to an istream
, remember it and delete it on destruction (and of course call push()
of the base class). Then just use and return the an instance of this subclass instead of boost::iostreams::filtering_istream
.
Upvotes: 1