Pattern to avoid circular reference?

K

Karthik V

I've been facing this situation often:

class NewFeature
{
TheClass *theClass;
NewFeature(TheClass *t) { theClass = t; }
void act() { // call methods on theClass }

}

class TheClass
{
NewFeature *feature; // More commonly, a list of NewFeature objects
AddFeature(NewFeature *f) { feature = f; // or append f to a list of
NewFeature objects }

}

In the above case, TheClass class contains pointers to NewFeature
objects, and each NewFeature object contains a pointer to the same
TheClass instance. This does seem to work most of the time but I'm not
comfortable with the idea of this circular reference.

Is there a standard design pattern to overcome this? The closest I saw
was visitor pattern. If I use that here, I'd do something like

class NewFeature
{
TheClass *theClass;
void accept(TheClass *t) { theClass = t; }
void act() { // call methods on theClass }

}

class TheClass
{
AddFeature(NewFeature *f) { f->accept(this); f->act(); }

}

But in this case, I'm losing the ability to keep track of the
NewFeature objects I have. Especially, if NewFeature.act() runs some
thread that calls TheClass methods later, I want TheClass to be able
to start / stop the thread when I want; so maintaining a list of those
pointers will be useful. If I do, I end up having my earlier code.

Please help!
 
A

adam.madram

I've been facing this situation often:

class NewFeature
{
TheClass *theClass;
NewFeature(TheClass *t) { theClass = t; }
void act() { // call methods on theClass }

}

class TheClass
{
NewFeature *feature; // More commonly, a list of NewFeature objects
AddFeature(NewFeature *f) { feature = f; // or append f to a list of
NewFeature objects }

}

In the above case, TheClass class contains pointers to NewFeature
objects, and each NewFeature object contains a pointer to the same
TheClass instance. This does seem to work most of the time but I'm not
comfortable with the idea of this circular reference.

Is there a standard design pattern to overcome this? The closest I saw
was visitor pattern. If I use that here, I'd do something like

class NewFeature
{
TheClass *theClass;
void accept(TheClass *t) { theClass = t; }
void act() { // call methods on theClass }

}

class TheClass
{
AddFeature(NewFeature *f) { f->accept(this); f->act(); }

}

But in this case, I'm losing the ability to keep track of the
NewFeature objects I have. Especially, if NewFeature.act() runs some
thread that calls TheClass methods later, I want TheClass to be able
to start / stop the thread when I want; so maintaining a list of those
pointers will be useful. If I do, I end up having my earlier code.

Please help!

There is nothing wrong with using your method. You have just keeping a
pointer to the object and not the actual object thus you have no
circular reference. All the pointer is in the most general sense is an
integer. Using the actual object would be bad though as this would be
like having a nested class structure and lead to looping in
compilation.
 
M

Michael DOUBEZ

(e-mail address removed) a écrit :
From a pure design point of view, you are right that it smells. But
sometimes, it is the more natural way of doing rather than go through
complex construction.

This often happen, as in your case a class owning a feature, when an
object has to keep a pointer on the object that owns it. The only
difficulty is lifetime issues: making the difference when a object is
destroyed by the object that own its or by other mean; there are many
strategy to adresse that.

Visitor tends to increase coupling between classes. I am pretty sure it
is not what you want.

The right solution greatly depends on what you want to achieve and the
environment you work in.
A generic solution (not the best for you) is defining an interface class
that is taken in parameter by a NewFeature. TheClass would inherit from
this interface and pass itself in parameter to the NewFeature.


You could also lookup "observer pattern" and signal/slot idiom. You
could also split your classes; it seems to me that TheClass has a lot of
responsibilities :start/stop thread, provides functions called into the
thread.
I can't help you there, it is your design.
There is nothing wrong with using your method. You have just keeping a
pointer to the object and not the actual object thus you have no
circular reference. All the pointer is in the most general sense is an
integer. Using the actual object would be bad though as this would be
like having a nested class structure and lead to looping in
compilation.

The OP problem is not from a compilation point of view but rather a
design issue.

Michael
 
K

Karthik V

(e-mail address removed) a écrit :




From a pure design point of view, you are right that it smells. But
sometimes, it is the more natural way of doing rather than go through
complex construction.

This often happen, as in your case a class owning a feature, when an
object has to keep a pointer on the object that owns it. The only
difficulty is lifetime issues: making the difference when a object is
destroyed by the object that own its or by other mean; there are many
strategy to adresse that.


Visitor tends to increase coupling between classes. I am pretty sure it
is not what you want.

The right solution greatly depends on what you want to achieve and the
environment you work in.
A generic solution (not the best for you) is defining an interface class
that is taken in parameter by a NewFeature. TheClass would inherit from
this interface and pass itself in parameter to the NewFeature.




You could also lookup "observer pattern" and signal/slot idiom. You
could also split your classes; it seems to me that TheClass has a lot of
responsibilities :start/stop thread, provides functions called into the
thread.
I can't help you there, it is your design.




The OP problem is not from a compilation point of view but rather a
design issue.

Michael

Michael and Adam,

Thanks a lot! As Michael said, the main concern was destroying the
object. Since the NewFeature can be extended and implemented by
anyone, there is a potential possibility of that code invoking a
Destroy() on TheClass. I was wondering if there is a way to prevent
that.

Michael, the way I have it now, TheClass is just an interface, not the
concrete implementation. So I guess I'm following that practice
already.
 
M

Michael DOUBEZ

Karthik V a écrit :
Michael and Adam,

Thanks a lot! As Michael said, the main concern was destroying the
object. Since the NewFeature can be extended and implemented by
anyone, there is a potential possibility of that code invoking a
Destroy() on TheClass. I was wondering if there is a way to prevent
that.

Declare the destructor of TheClass protected.
Michael, the way I have it now, TheClass is just an interface, not the
concrete implementation. So I guess I'm following that practice
already.

Michael
 
T

terminator

Karthik V a écrit :



Declare the destructor of TheClass protected.




Michael

why not to refrence count 'TheClass'(e.g using boost::shared_ptr)?

regards,
FM.
 
J

James Kanze

(e-mail address removed) a écrit :
From a pure design point of view, you are right that it smells. But
sometimes, it is the more natural way of doing rather than go through
complex construction.

Why? It looks like a more or less standard implementation of
the strategy pattern. Most of the time, the strategy
elements---the NewFeature here---don't need a reference to the
parent, but I don't see any particular problem when they do.

Most of the time, of course, NewFeature will be an abstract base
class; in such cases, it's often simplest to make it a member
class of TheClass. (Not that this changes much in overall
view.)
This often happen, as in your case a class owning a feature,
when an object has to keep a pointer on the object that owns
it. The only difficulty is lifetime issues: making the
difference when a object is destroyed by the object that own
its or by other mean; there are many strategy to adresse that.

The usual solution is to have the TheClass construct the
NewFeature, via some special function, and then own it, deleting
it in its destructor.
Visitor tends to increase coupling between classes. I am
pretty sure it is not what you want.

I don't think it's what he's looking for either, but not because
of coupling. In his case, the coupling is there (since
NewFeature depends on TheClass).

In the past, I've used a variant of this several times, in which
NewFeature was an abstract base class, member and friend of
TheClass, and it provided an extended interface to TheClass, so
that user code could implement a wide variety of strategies.

If the NewFeature objects are polymorphic (and I don't see very
well how they could not be), then in practice, they'll all be
allocated on the stack. The usual solution in my code is just
to let the garbage collector take care of them, but if for some
reason you cannot use garbage collection, it's typically not too
much of a constraint to require them to be unique to each
instance, and have TheClass take over ownership, and delete them
in the destructor. (I'd document this by having the function
which registers them take an auto_ptr.) Some sort of reference
counting could also be used, but typically, it's overkill.

If the NewFeature uses worker threads, you have a whole lot of
additional issues to address. Like what happens if the TheClass
object is deleted before the worker thread has finished.

One solution I've used at times is to make the destructor of
TheClass private, and require calling a special member function
to destroy the object. This function marks the object as
"dead", and puts it on a queue for destruction; actual
destruction only occurs when the last worker thread has
finished. It's not a universal solution, however, and isn't
always appropriate.

(Trying to do multithreading without garbage collection is just
plain stupid.)
You could also lookup "observer pattern" and signal/slot
idiom. You could also split your classes; it seems to me that
TheClass has a lot of responsibilities :start/stop thread,
provides functions called into the thread. I can't help you
there, it is your design.

Making the observer pattern work well between threads is far
from trivial.
 
J

James Kanze

why not to refrence count 'TheClass'(e.g using boost::shared_ptr)?

What does that solve (except introduce a lot of constraints in
the use of TheClass).
 

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

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,074
Latest member
StanleyFra

Latest Threads

Top