views:

110

answers:

6

Does anyone know any trick I could use to keep the Derived class until the base class destructor have been called?

i.e:

#include <iostream.h>
class Base
{
       public:
          Base(){ cout<<"Constructor: Base"<<endl;}
          virtual ~Base(){ cout<<"Destructor : Base"<<endl;}
};
class Derived: public Base
{
     //Doing a lot of jobs by extending the functionality
       public:
           Derived(){ cout<<"Constructor: Derived"<<endl;}
           ~Derived(){ cout<<"Destructor : Derived"<<endl;}
};
void main()
{
        Base *Var = new Derived();
        delete Var;
}

This will result in Derived class to be destroyed, then Base class will be destroyed.

The reason I need something like this is I have a custom Event(signal/slot) class.

The Event class provide an Observer class.

If I define :

class A : public Event::Observer

and then delete an instance of class A, when the ~Observer automatically remove any signal connected to this observer.

But since Class A is destroyed before the Observer, if something on a different thread call a slot on A after ~A and before ~Observer get called. Everything goes to hell...

I can always call the Observer.release method from the ~A, which fix the timing issue. But it was cleaner if I wouldnt need to.

Any ideas?

+2  A: 

Destructors work as they are expected to do and you should not touch them (actually, you can't change the calling order). As for your task - you need proper threads synchronization. As a simplest solution: unsubscribe your observer before deleting it.

Gobra
+2  A: 

I suggest you either implement reference counting or an IDisposable interface and use it as a convention amongst your clients. Whether or not you call Observer::Release() in your A::dtor(), YOu're talking about having a different thread come in and call a method on an object that is being destroyed. That is definitely a race condition, you should never have code from another thread asynchronously executing on a method on an object that is being destroyed.

With reference counting, the event subscriber objects don't get deleted until they are unregistered. With an IDisposable pattern, you make sure to remove any references to an object before the destructor is called. Either could be appropriate depending on your architecture.

David Gladfelter
A: 

Base class destructor always gets called after derived class destructor. You mustn't call any of object's methods from other threads after object's destructor begins execution (regardless of whether it has a base class or not). I'd suggest using a new class that works as a container for class Base instances and implements a safe access to Base's objects (you probably need to use one of synchronization objects to implement id).

a1ex07
+4  A: 

You definitely don't want to change destruction order, which is good, because you can't.

What you really want to do is to dispose/disconnect/shutdown the Observer.

What I would do is add this to your Event::Observer class:


void Event::Observer::Shutdown()
{
    if(!isShutdown)
    {
        //Shut down any links to this observer
        isShutdown = true;
    }
}

void ~Event::Observer()
{
    Shutdown();
    //rest of Event::Observer destruction
}

and then:


~A()
{
    Shutdown();
    //clean up any other A resources
}

If you did something like IDisposable suggested by David, that would work too -- just call Observer::Dispose() in your destructor for class A.

My code all assumes that you have only a single thread accessing these objects. Thread synchronization is an entirely separate subject.

Andrew Shelansky
Seem like I cannot call the Observer destructor first, so Calling it in every destructor of class that use ::Observer is the next best possibility.
JP
Uhm... the assumption that there is a single thread is surely wrong, since if there was a single thread in the application then the order of destruction would be irrelevant. Anyway +1 since this points to a solution --that should be improved in real code with thread safety.
David Rodríguez - dribeas
A: 

You cannot change the order of destruction in an inheritance relationship and that's good (what would a Derived be once its Base was destroyed?. However, you can change the relationship.

For example you could always wrap Derived in a class (template) which calls release() first before destroying Derived.

sbi
A: 

It's a typical race condition, it's just that this one is glaring.

There are obviously several methods at your disposal. You could for example have a mutex in the Base class and lock it as soon as you enter the destructor of the most derived class... however as you noted it's difficult.

I would suggest making the destructor protected (for each class in the hierarchy) and have a method to invoke for destruction (objects cannot be allocated on the stack any longer), then overload delete for the Base class, and have it unregister your object first before destroying it by calling this special method.

The only issue is that anyone not respecting the make your destructor protected bit will screw things up.

On the other hand, you could also NOT use inheritance, and prefer composition instead. This would allow you to control the destruction order of the various attributes.

Matthieu M.