Here's a problem scenario: I've got a C++ object that includes a Cleanup() virtual method that needs to be called just before the object is destroyed. In order to do the right thing, this Cleanup method needs access to the fully-formed object (including subclass data), so I can't just call Cleanup() at the start of my own class's destructor, because by the time my class's destructor is called, the destructors any subclasses have already completed and they may have already freed some data that Cleanup() needed to look at.
The obvious solution would be to require the calling code to manually call my routine before deleting the object:
theObject->Cleanup();
delete theObject;
but that solution is fragile, since sooner or later somebody (probably me) will forget to call Cleanup() and bad things will happen.
Another solution would be to have a "holder" object that implements the pImpl technique to wrap the class, and have the holder object's destructor call Cleanup() on the object before deleting the object; but that solution isn't 100% desirable either, since it makes the class work differently from a standard C++ class and makes it impossible to allocate the object on the stack or statically.
So the question is, is there some clever technique (either in C++ or C++11) that I could use to tell the compiler to automatically call a specified (presumably virtual) method on my object before it calls the first subclass-destructor?
(come to think of it, a similar mechanism for automatically calling an Init() method -- just after the last subclass-constructor completes -- might be handy as well)
Lateral thinking: get rid of the Cleanup method, that's what a virtual destructor is for.
The very goal of a virtual destructor is to allow the outmost derived class destructor to be called when delete basepointer; is executed; and as RAII demonstrated, cleanup is the destructor's job.
Now you might argue that you would like an early Cleanup method, to ease the task of the destructor or maybe to reuse the object (kinda like a Reset method in a way). In practice, it rapidly turns into a maintenance nightmare (too easy to forget to clean one field and have state leak from one use to another).
So ask yourself the question: Why not use the destructor for what it's been created for ?
You can use a twist on the PIMPL wrapper:
class PIMPL
{
MyDataThatNeedsInitDestroy object;
public:
PIMPL(Atgs a)
: object(a)
{
object.postCreationInit();
}
~PIMP()
{
object.preDestructionDestory();
}
// All other methods are available via -> operator
MyDataThatNeedsInitDestroy* operator->() { return &object);
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With