virtual destructor 101
Just recently I started to review my memory management "habits"
and how to improve them. Especially with the concept of
"allocator" and incoming C++0x smart pointers.
One concern is how a virtual destructor fits into the world.
Let me start with one interface:
class Stack {
public:
virtual void push(int value) = 0;
virtual int top() const = 0;
virtual void pop() = 0;
};
(Before pointing me to the C++ FAQ right here, I will clarify that
this is only for the sake of argument -- I always add a virtual
destructor).
What happens if we don't put a virtual destructor... The (low-level)
effect is that we cannot use "delete" via a pointer to Stack.
But what if we do not want to allow such "delete"? What if we want
to provide an implementation that handles instances in its own way?
Example 1: Who said MS?
Stack * CreateStack1();
void DeleteStack1(Stack *);
Example 2: The general solution
std::shared_ptr<Stack> CreateStack2();
We all know that shared_ptr can be used for any conceivable method
of creating and destroying an object. Furthermore, even the simplest
usage of shared_ptr does not require a public virtual destructor as
it will use the destructor of the implementation class.
This was just an introduction. Now comes my dilemma...
If we put a virtual destructor in the Stack (which I would as
I mentioned before), someone might think that this is a part of
the interface and use "delete" even when not supposed to. I know such
usage would be ill-formed and should be made clear in the documentation
who owns which, but let's just say that it may look a bit tempting
and let it be an introduction for the following...
How about if someone tried to forbid using "delete" and put
the virtual destructor as protected. This would make a much safer code
and would still allow implementations that could be handled by
the two mentioned examples. Of course, derived classes could still
be managed by the new/delete pair. It sound like a good and
a bulletproof solution.
But... making a virtual destructor protected actually tries to
enforce a specific memory management, or at least prohibit
the trivial "delete by pointer to base" interface which is completely
valid type of memory management. IMHO this is not something one should
decide or put into an interface describing a Stack. Some implementations
may want to do memory management one way, while others would want
to do it the other way.
Doesn't it look like the decision of making the destructor virtual
or not, public or protected, has to be made in the wrong place in
the design? An interface describing a Stack should be free of such
decision, right?
Hope I managed to express myself well...
Thanks and sorry for reading so much text! Looking forward
to further discussion...
--
Dragan
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]