PHWinfo banniere

Titres
PORTAIL ANNUAIRE ARTICLES COMPARATEUR HÉBERGEURS DEVIS FORUMS RÉDUCTEUR D'URL
Précédent   PHWinfo > Autres forums > Forum Programmation & Conception > comp.lang.cplus > Pattern to avoid circular reference?
S'inscrire FAQ Membres Recherche Messages du jour Marquer les forums comme lus
Pattern to avoid circular reference?

Réponse
 
LinkBack Outils de la discussion
Vieux 07/12/2007, 04h01   #1
Karthik V
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Pattern to avoid circular reference?

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 !
  Réponse avec citation
Vieux 07/12/2007, 04h35   #2
adam.madram@gmail.com
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Pattern to avoid circular reference?

On Dec 6, 10:01 pm, Karthik V <karthikveeram...@gmail.com> wrote:
> 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 !


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.
  Réponse avec citation
Vieux 07/12/2007, 08h08   #3
Michael DOUBEZ
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Pattern to avoid circular reference?

adam.madram@gmail.com a écrit :
> On Dec 6, 10:01 pm, Karthik V <karthikveeram...@gmail.com> wrote:
>> 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.


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.

>> Is there a standard design pattern to overcome this? The closest I saw
>> was visitor pattern.


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.


>> 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.


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 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
  Réponse avec citation
Vieux 07/12/2007, 17h29   #4
Karthik V
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Pattern to avoid circular reference?

On Dec 7, 12:08 am, Michael DOUBEZ <michael.dou...@free.fr> wrote:
> adam.mad...@gmail.com a écrit :
>
>
>
> > On Dec 6, 10:01 pm, Karthik V <karthikveeram...@gmail.com> wrote:
> >> 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.

>
> 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.
>
> >> Is there a standard design pattern to overcome this? The closest I saw
> >> was visitor pattern.

>
> 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.
>
>
>
> >> 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.

>
> 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 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


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.


  Réponse avec citation
Vieux 08/12/2007, 21h47   #5
Michael DOUBEZ
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Pattern to avoid circular reference?

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
  Réponse avec citation
Vieux 09/12/2007, 11h48   #6
terminator
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Pattern to avoid circular reference?

On Dec 9, 12:47 am, Michael DOUBEZ <michael.dou...@free.fr> wrote:
> 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


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

regards,
FM.
  Réponse avec citation
Vieux 09/12/2007, 13h33   #7
James Kanze
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Pattern to avoid circular reference?

On Dec 7, 9:08 am, Michael DOUBEZ <michael.dou...@free.fr> wrote:
> adam.mad...@gmail.com a écrit :


> > On Dec 6, 10:01 pm, Karthik V <karthikveeram...@gmail.com> wrote:
> >> 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.


> 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.

> >> Is there a standard design pattern to overcome this? The
> >> closest I saw was visitor pattern.


> 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 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.


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.

> >> 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.


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 you
> there, it is your design.


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

--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
  Réponse avec citation
Vieux 09/12/2007, 13h34   #8
James Kanze
Aucun Avatar
 
Messages: n/a
Hébergeur:
Par défaut Re: Pattern to avoid circular reference?

On Dec 9, 12:48 pm, terminator <farid.mehr...@gmail.com> wrote:
> On Dec 9, 12:47 am, Michael DOUBEZ <michael.dou...@free.fr> wrote:
> > 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.


> 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).

--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
  Réponse avec citation
Réponse


Outils de la discussion

Règles de messages
Vous ne pouvez pas créer de nouvelles discussions
Vous ne pouvez pas envoyer des réponses
Vous ne pouvez pas envoyer des pièces jointes
Vous ne pouvez pas modifier vos messages

Les balises BB sont activées : oui
Les smileys sont activés : oui
La balise [IMG] est activée : oui
Le code HTML peut être employé : non
Trackbacks are oui
Pingbacks are oui
Refbacks are oui


Fuseau horaire GMT +1. Il est actuellement 19h10.


Édité par : vBulletin® version 3.7.3
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Search Engine Friendly URLs by vBSEO 3.2.0 RC5 Tous droits réservés.
Version française #16 par l'association vBulletin francophone
PHWinfo est un site Éducation Sans Frontières ©2000-2008
Ad Management by RedTyger
©Tous droits réservés par les parties respectives
Page generated in 0,21717 seconds with 16 queries