Consider the following class structure:
class Filter
{
virtual void filter() = 0;
virtual ~Filter() { }
};
class FilterChain : public Filter
{
FilterChain(collection<Filter*> filters)
{
// copies "filters" to some internal list
// (the pointers are copied, not the filters themselves)
}
~FilterChain()
{
// What do I do here?
}
void filter()
{
// execute filters in sequence
}
};
I’m exposing the class in a library, so I don’t have control over how it will be used.
I’m currently having some design issues regarding ownership of the Filter objects FilterChain is holding pointers to. More specifically, here are two possible usage scenarios for FilterChain:
- Scenario A: some of the functions in my library are constructing a (possibly complex) filter chain, allocating memory as necessary, and returning a newly-allocated
FilterChainobject. For example, one of these functions constructs a filter chain from a file, which can describe arbitrarily-complex filters (including filter chains of filter chains, etc.). The user of the function is responsible for object destruction once the job is done. - Scenario B: the user has access to a bunch of
Filterobjects, and wants to combine them in filter chains in a specific manner. The user constructsFilterChainobjects for its own use, then destroy them when he’s done with them. TheFilterobjects must not be destroyed when aFilterChainreferencing them is destroyed.
Now, the two simplest ways to manage ownership in the FilterChain object are:
FilterChainown theFilterobjects. This means the objects referenced byFilterChainare destroyed inFilterChain‘s destructor. Which is incompatible with scenario B.FilterChaindoes not own theFilterobjects. This meansFilterChain‘s destructor does nothing. Now there is a problem with scenario A, because the user would have to know the internal structure of all theFilterobjects involved in order to destroy them all without missing one, as the parentFilterChaindoes not do it itself. That’s just bad design, and asking for memory leaks.
Consequently, I need something more complicated. My first guess is to design a smart pointer with a settable boolean flag indicating whether or not the smart pointer owns the object. Then instead of taking a collection of pointers to Filter objects, FilterChain would take a collection of smart pointers to Filter objects. When FilterChain‘s destructor is called, it would destroy the smart pointers. The destructor of the smart pointer itself would then destroy the object being pointed to (a Filter object) if and only if the boolean flag indicating ownership is set.
I get the feeling that this problem is commonplace in C++, but my web searches for popular solutions or clever design patterns were not very successful. Indeed, auto_ptr doesn’t really help here and shared_ptr seems overkill. So, is my solution a good idea or not?
Smart pointers here are not overkill: obviously you have a design problem that one way or another needs careful consideration of object lifetimes and ownership. This would be especially true if you want the ability to re-patch filters in the filter graph at runtime, or the ability to create compound
FilterChainobjects.Using
shared_ptrwill remove most of those issues in one swoop and make your design a lot simpler. The only potential gotcha I think here is if your filter happens to contain cycles. I can see that could happen if you have some kind of feedback loop. In that instance I would suggest having allFilterobjects owned by a single class, and then theFilterChainwould store weak pointers to theFilterobjects.I would wager that the execution time of the filter stages would be far in excess of the extra overhead of dereferencing a smart pointer.
shared_ptris designed to be pretty lightweight.