Force method call in destructor of a derived class?

D

Daniel Kay

Hello!

I have written two template classes which implement the observerpattern
in C++. I hope I manage to desribe the problem I have.

template<class T> class Observer {
/* ... */
};

template<class T> classSubject {
/* ... */
};

These template classes are being used as base classes for non abstract
Observer and Subject classes. The update() method in the observer class
is pure virtual and needs to be implemented by the class which derives
the Observer template class. This is good, because the user can't forget
to implement it.

In my concept the subject has a list of attached observers, and the
Observer has a list of subject it was attached to. When a observer is
destructed for some reason, the destructor detaches itself from all
Subjects it was attached to.

Now my problem: At that point, when I am in the destructor of the
Observer template, the update method isn't available anymore. (Because
the derived class is already destructed) So in case the Subject now
tries to notify the observer the application crashes. Of course this
only happens with a multithreaded application. In normal case this
condition will happen very very seldom. But it can and will happen some
day. I have found two ways to resolve this issue. I don't like one of them.

1. Make the method update() in the observer base class virtual only
(defining an empty body). The user isn't forced anymore to implement
update in the derived class of the Observer pattern and might forget it.

2. By forcing the user to call some method from the destructor of the
derived class which was defined in the Observer base class which
detaches itself from all Subjects. The user may forget to insert this
call in his destructor and we have the problem again.

Anyone knows a third way to resolve my problem? I hope I managed to
describe my problem... :D If not, then just ignore it and i am lost... *g*

Have a nice day,
Daniel
 
A

Alf P. Steinbach

* Daniel Kay:
[long problem description]

The short of it seems to be: you need some notification when the client code's
derived class object is destroyed.

And one way to do that is to force the client code to use a special template
class as the most derived class.

Client code:

class MyObserverImpl: public Observer { ... };
typedef ConcreteObserver<MyObserverImpl> MyObserver;

where ConcreteObserver is a template class you provide, where the destructor
provides the notification you need.

You can force use of ConcreteObserver via the virtual base class with private
constructor and friend trick, described in the FAQ for the case of disallowing
further inheritance -- making a class "final" or "sealed" -- but I think
more useful for the case above, forcing a given most derived class.

One main problem with this technique is how to forward constructor arguments
from ConcreteObserver to, in the example above, MyObserverImpl. And one
solution is to require that every constructor except the default constructor
must have exactly one argument (which can be a struct), and then use a
templated constructor. There are also other solutions.
 
D

David Hilsee

Daniel Kay said:
Hello!

I have written two template classes which implement the observerpattern
in C++. I hope I manage to desribe the problem I have.

template<class T> class Observer {
/* ... */
};

template<class T> classSubject {
/* ... */
};

These template classes are being used as base classes for non abstract
Observer and Subject classes. The update() method in the observer class
is pure virtual and needs to be implemented by the class which derives
the Observer template class. This is good, because the user can't forget
to implement it.

In my concept the subject has a list of attached observers, and the
Observer has a list of subject it was attached to. When a observer is
destructed for some reason, the destructor detaches itself from all
Subjects it was attached to.

Now my problem: At that point, when I am in the destructor of the
Observer template, the update method isn't available anymore. (Because
the derived class is already destructed) So in case the Subject now
tries to notify the observer the application crashes. Of course this
only happens with a multithreaded application. In normal case this
condition will happen very very seldom. But it can and will happen some
day. I have found two ways to resolve this issue. I don't like one of them.

1. Make the method update() in the observer base class virtual only
(defining an empty body). The user isn't forced anymore to implement
update in the derived class of the Observer pattern and might forget it.

2. By forcing the user to call some method from the destructor of the
derived class which was defined in the Observer base class which
detaches itself from all Subjects. The user may forget to insert this
call in his destructor and we have the problem again.

Anyone knows a third way to resolve my problem? I hope I managed to
describe my problem... :D If not, then just ignore it and i am lost... *g*

Have a nice day,
Daniel

You shouldn't allow other threads to invoke member functions on an object
that is destructing unless you have a guarantee from your implementation
that the "behind the scenes" work that your implementation provides for
destruction is thread-safe. Your implementation may be messing with the
vtable or doing other things when you invoke one of the functions. You
should remove the observer from the subject before object destruction
begins.
 
D

Daniel Kay

Alf said:
* Daniel Kay:
[long problem description]


The short of it seems to be: you need some notification when the client code's
derived class object is destroyed.

And one way to do that is to force the client code to use a special template
class as the most derived class.

Client code:

class MyObserverImpl: public Observer { ... };
typedef ConcreteObserver<MyObserverImpl> MyObserver;

where ConcreteObserver is a template class you provide, where the destructor
provides the notification you need.

You can force use of ConcreteObserver via the virtual base class with private
constructor and friend trick, described in the FAQ for the case of disallowing
further inheritance -- making a class "final" or "sealed" -- but I think
more useful for the case above, forcing a given most derived class.

One main problem with this technique is how to forward constructor arguments
from ConcreteObserver to, in the example above, MyObserverImpl. And one
solution is to require that every constructor except the default constructor
must have exactly one argument (which can be a struct), and then use a
templated constructor. There are also other solutions.

Thank you for your spare time on giving me some idea on how to solve my
problem. If no better solutions is being posted I'll try to implement it.

Thx,
Daniel
 
D

Daniel Kay

David said:
You shouldn't allow other threads to invoke member functions on an object
that is destructing unless you have a guarantee from your implementation
that the "behind the scenes" work that your implementation provides for
destruction is thread-safe. Your implementation may be messing with the
vtable or doing other things when you invoke one of the functions. You
should remove the observer from the subject before object destruction
begins

Hello David!

Right now the destructor of the observer base class does the following
to protect itself from calling subjects.

Make sure that all subjects the observer is attached to won't try to
call the update() method by invoking the lock() method of all subject
instances. Then I detach from all subjects. Then I invoke unlock() for
all subjects, so they can continue their work.

The time between destructing the derived instance and locking all
subjects is critical. Of course one solution is to call a method defined
in the observer base class before I destruct the derived class. But
there must be a better way in resolving this problem.

Bye,
Daniel Kay
 
D

David Hilsee

[...]
Hello David!

Right now the destructor of the observer base class does the following
to protect itself from calling subjects.

Make sure that all subjects the observer is attached to won't try to
call the update() method by invoking the lock() method of all subject
instances. Then I detach from all subjects. Then I invoke unlock() for
all subjects, so they can continue their work.

The time between destructing the derived instance and locking all
subjects is critical. Of course one solution is to call a method defined
in the observer base class before I destruct the derived class. But
there must be a better way in resolving this problem.

OK, I just wanted to make sure that you understood that "solution" #1
suffers from multithreading issues.

I suppose you could always write a little handle class that holds on to the
observer and does the work for you. In its destructor, you could detach the
observer from the subjects before you destruct the object. Then you always
hold on to observers using that wrapper class instead of just using the
Observer class.

class ObserverHandle {
Observer * observer;

//...
~ObserverHandle() {
observer->DetachFromSubjects();
delete observer;
}
};
 
G

Greg

Daniel said:
Hello!

I have written two template classes which implement the observerpattern
in C++. I hope I manage to desribe the problem I have.

template<class T> class Observer {
/* ... */
};

template<class T> classSubject {
/* ... */
};

These template classes are being used as base classes for non abstract
Observer and Subject classes. The update() method in the observer class
is pure virtual and needs to be implemented by the class which derives
the Observer template class. This is good, because the user can't forget
to implement it.

In my concept the subject has a list of attached observers, and the
Observer has a list of subject it was attached to. When a observer is
destructed for some reason, the destructor detaches itself from all
Subjects it was attached to.

Now my problem: At that point, when I am in the destructor of the
Observer template, the update method isn't available anymore. (Because
the derived class is already destructed) So in case the Subject now
tries to notify the observer the application crashes. Of course this
only happens with a multithreaded application. In normal case this
condition will happen very very seldom. But it can and will happen some
day. I have found two ways to resolve this issue. I don't like one of them.

1. Make the method update() in the observer base class virtual only
(defining an empty body). The user isn't forced anymore to implement
update in the derived class of the Observer pattern and might forget it.

2. By forcing the user to call some method from the destructor of the
derived class which was defined in the Observer base class which
detaches itself from all Subjects. The user may forget to insert this
call in his destructor and we have the problem again.

Anyone knows a third way to resolve my problem? I hope I managed to
describe my problem... :D If not, then just ignore it and i am lost... *g*

Have a nice day,
Daniel

Why not implement Observer::Update() but keep it a pure virtual
function so subclasses still have to implement it themselves?

Greg
 
D

Daniel Kay

Greg said:
Why not implement Observer::Update() but keep it a pure virtual
function so subclasses still have to implement it themselves?

I don't understand...

class PureVirtualMethod {
virtual void update(Subject* s) = 0;
};

class VirtualMethod {
virtual void update(Subject* s) { };
};

I am not forced to define an own version of update(Subject* s) with the
second class. Or is there any way to define it in the base class but
also force the user to define his own? Would be new to me.

Today I had a look at the boost libraries. And I had a look at
signal/slot template which seems simular to the technique used by QT.
Maybe that's the solution for my problem. Thanks to everyone...

Cya,
Daniel Kay
 
R

red floyd

Daniel said:
class PureVirtualMethod {
virtual void update(Subject* s) = 0;
};

As I understand it, the following is legal;

class PureVirtualMethod {
public:
virtual void update(Subject* s) = 0;
};

void PureVirtualMethod::update(Subject* s)
{
// some implementation
}

class NonPure : public PureVirtualMethod
{
public:
void update(Subject* s)
{
// my implementation specific details here
// followed by common code
PureVirtualMethod::update(s);
}
};
 
G

Greg

Daniel said:
I don't understand...

class PureVirtualMethod {
virtual void update(Subject* s) = 0;
};

class VirtualMethod {
virtual void update(Subject* s) { };
};

I am not forced to define an own version of update(Subject* s) with the
second class. Or is there any way to define it in the base class but
also force the user to define his own? Would be new to me.

I bet that you would not be the only C++ programmer to be surprised by
the fact that pure virtual functions can be defined. In fact, sometimes
a pure virtual function must be defined, according to the Standard:

A pure virtual function need be defined only if
explicity called with the qualified-id syntax. [10.4.2]

In other words, if Observer::update() is called explicitly from
anywhere than that pure virtual function must be defined. Otherwise
defining it is optional. Since the program is crashing because
Observer::update is not defined, defining Observer::update() should fix
the crash with only three lines of empty code:

void Observer::update()
{
// do nothing
}

Note that the pure virtual syntax prevents the definition and the
declaration from being combined. So the definition of a pure virtual
function must always appear on its own.

In fact a pure virtual function can override a non-pure function in a
base class. So Observer could inherit from a base class with a nonpure
update() that it would override with a pure update(). But it is simpler
just for Observer to implement update() itself as a pure virtual
function, than to implement a more complicated solution.

Greg
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top