Reputation: 2115
I would like to make sure no one is able to delete any objects from my class hierarchy other then by using a provided Destroy method.
The rationale is that any object from this hierarchy needs to take a special write mutex before it starts to destroy itself to make sure objects are not deleted while another thread is using them.
I know I could prevent this problem with reference counting but it would be a much bigger change to the system also in terms of potential performance impact and memory allocation.
Is there a way to somehow efficiently/smartly make all the destructors protected so that child classes can call their parents destructors while outsiders have to use Destroy?
One solution that is safe (ie. it will not rot) that I came up with is to make all the destructors private and declare each derived class as a friend of the base class but I'd prefer something more elegant, less manual and easier to maintain (like not requiring to modify base classes in order to derive from them).
Is there anything like this available? Maybe some smart trick that makes things "work" as I'd like?
ps. The solution I chose for now is to NOT prevent anyone from calling delete in all cases (just made it protected in the base class) but detect this situation and call abort in the base class destructor.
Upvotes: 5
Views: 219
Reputation: 6897
I had the same needs, but for a different reason. In our company framework, nearly all classes derive from a common BaseObject
class. This object uses a reference count to determine its life time. BaseObject
has in particular these three methods: retain()
, release()
and autorelease()
, heavily inspired from Objective-C language. The operator delete
is only called inside release()
when the retain count reaches 0. Nobody is supposed to call delete
directly, and it is also undesirable to have BaseObject
instances on stack.
Therefore, all our destructors should be protected
or private
. To enforce this, as I know it is impossible from the language, I wrote a Perl script that looks for all destructors within a source directory and makes a report. It is then relatively easy to check that the rule is respected.
I made the script public, available here: https://gist.github.com/prapin/308a7f333d6836780fd5
Upvotes: 1
Reputation: 2115
Thanks for all your feedback and discussion. Yes - it proved it's impossible to do what would be my natural first choice :( (to have the "protection" of the destructor take effect in derived classes just as it's "virtuality" does).
My solution in this particular case (solving all potential problems with being able to make hones mistakes by introducing new derived classes that violate previous agreements AND keeping the solution in one place/maintainable (no code duplication in derived classes etc)) is:
Upvotes: 1
Reputation: 2767
It can be done with help of testing. For a class with an protected destructor you need 2 test cases:
If both test cases work I think you can be sure your classes are protected as you like.
I don't know wether you are able to implement it with your build system but I have an example using bjam (from boost) at git hub. The code is simple and works for gcc and msvc. If you don't know bjam you should look inte Jamroot.jam. I think it is clear without any further comment how this simple example works.
Upvotes: 0
Reputation: 24163
Don't try to reinvent the lifetime mechanisms provided by the language.
For an object of your class to be correctly initialised it needs to also be able to clean itself up.
In its constructor pass either the mutex, or a means of obtaining a mutex, which it can use in its destructor.
Upvotes: 1