 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
christian.siegl@gmail.com Guest
|
Posted: Sat Oct 15, 2005 1:28 pm Post subject: How to delete yourself??? |
|
|
Hello,
I got a strange problem, which should be quite ordinary but I don't
know how to handle it....
I have got two classes, a parent and a child. The child needs a
function to delete itself.... The question is, whether or not this is
possible....
Asume we have the following code:
//////////////////////////////////////////////////////
class parent;
class child
{
public:
child();
~child();
parent* pp;
void DeleteMe(void)
{
pp->DeleteChild(this);
}
};
class parent
{
public:
parent();
~parent();
child* ary_c[1000]; // something like that....
void DeleteChild(child *pc)
{
// delete child from the array here and delete its instance....
// however this is done here.... its not important....
}
};
////////////////////////////////////////////////////////////////////////
So the big question is, is this code rubbish or not??? I mean it works,
because I don't touch any member variables from class child. But is
this nice code??? Is there a different way to handle this problem???
Thanks very much for any comments....
Chris
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
AnonMail2005@gmail.com Guest
|
|
| Back to top |
|
 |
Gene Bushuyev Guest
|
Posted: Sun Oct 16, 2005 9:33 am Post subject: Re: How to delete yourself??? |
|
|
<christian.siegl (AT) gmail (DOT) com> wrote
[...]
| Quote: | class parent;
class child
{
public:
child();
~child();
parent* pp;
void DeleteMe(void)
{
pp->DeleteChild(this);
}
};
class parent
{
public:
parent();
~parent();
child* ary_c[1000]; // something like that....
void DeleteChild(child *pc)
{
// delete child from the array here and delete its instance....
// however this is done here.... its not important....
}
};
////////////////////////////////////////////////////////////////////////
So the big question is, is this code rubbish or not??? I mean it works,
because I don't touch any member variables from class child. But is
this nice code??? Is there a different way to handle this problem???
|
No it's not a nice code Not that it will not work, but the design is
definitely suspicious. The first thing you need to remember, the class that owns
the object is responsible for its deletion. That is, your "child" objects should
never decide to delete themselves. The algorithm should ask "parent" object to
erase them. By the same token, I would subject "parent* child::pp" to
examination. Why would "child" need to know about the "parent"? You shouldn't
need it. Finally, why not to use a standard or boost container, that not only
creates a cleaner and leaner code, but will also steer you into the right design
decisions. And, for Pete's sake, don't make everything public.
-- Gene
----------------------------------------------------------------
There is no greatness where there is no simplicity, goodness and truth. ~ Leo
Tolstoy
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Malte Clasen Guest
|
Posted: Sun Oct 16, 2005 9:34 am Post subject: Re: How to delete yourself??? |
|
|
[email]christian.siegl (AT) gmail (DOT) com[/email] wrote:
| Quote: | I got a strange problem, which should be quite ordinary but I don't
know how to handle it....
I have got two classes, a parent and a child. The child needs a
function to delete itself.... The question is, whether or not this is
possible....
|
I wonder whether this design is necessary in the first place. I'm under
the impression that an object should only be deleted by it's owner - let
it a shared pointer or whatever. This perspective suggests that an
object who wants to delete itself has to be it's own owner - which in
turn is usually the case with singletons but I've never noticed it in
other designs. Since your child class is obviously not a singleton, why
should it be master of his own span of existence? Especially when it
doesn't construct itself and never get's its own ownership transferred
explicitly. All things considered this looks quite strange to me and I'd
be glad to see some real-world examples where this idiom is considered
useful.
Malte
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
James Kanze Guest
|
Posted: Sun Oct 16, 2005 9:49 am Post subject: Re: How to delete yourself??? |
|
|
[email]christian.siegl (AT) gmail (DOT) com[/email] wrote:
| Quote: | I got a strange problem, which should be quite ordinary but I
don't know how to handle it....
I have got two classes, a parent and a child. The child needs
a function to delete itself.... The question is, whether or
not this is possible....
|
Where's the problem? It's a frequent requirement in any OO
design, and delete this works perfectly well.
| Quote: | Asume we have the following code:
//////////////////////////////////////////////////////
class parent;
class child
{
public:
child();
~child();
parent* pp;
void DeleteMe(void)
{
pp->DeleteChild(this);
}
};
class parent
{
public:
parent();
~parent();
child* ary_c[1000]; // something like that....
void DeleteChild(child *pc)
{
// delete child from the array here and delete its instance....
// however this is done here.... its not important....
}
};
////////////////////////////////////////////////////////////////////////
So the big question is, is this code rubbish or not??? I mean
it works, because I don't touch any member variables from
class child. But is this nice code??? Is there a different
way to handle this problem???
|
Having the child do delete this, with notification code in the
destructor, is probably cleaner. It makes it more obvious to
the maintenance programmer what is going on.
--
James Kanze mailto: [email]james.kanze (AT) free (DOT) fr[/email]
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Peter_Julian Guest
|
Posted: Sun Oct 16, 2005 3:51 pm Post subject: Re: How to delete yourself??? |
|
|
<christian.siegl (AT) gmail (DOT) com> wrote
| Quote: | Hello,
I got a strange problem, which should be quite ordinary but I don't
know how to handle it....
I have got two classes, a parent and a child. The child needs a
function to delete itself.... The question is, whether or not this is
possible....
|
You are describing a container/element relationship, not a Parent/Child
relationship.
The elements don't need a delete() member function because they already
have one. Its called a destructor.
Basicly, the element destroys itself by calling the appropriate
container behaviour with itself as a parameter. The goal here is not to
have elements control the container but rather have the container manage
the elements. Life is much simpler that way. He who controls the
container then controls everything.
A little effort is worth taking in designing, or rather choosing, your
container. Lets suppose for the sake of discussion that you require a
simple, fast container that doesn't store duplicates and does *not* rely
on heap allocations (new - delete). Furthermore, you want that container
to be able to hold anything (not just integers). Why? You can reuse the
same container class for any variety of user types (certain caveats
apply). Lets also complicate the matter further and reinforce the
container's security. Only the container's interface can allow access to
the elements within. The container is the manager and the security
department.
The key is how you design the Element class (the one you keep calling
the Child class). For this container, an associative container like
std::set is the perfect candidate but that means you need to match
requirements.
The Element class requires a ctor, a d~tor, a copy ctor, an assignment
operator as well as a few friends to help it satisfy the requirements of
a default std::set (operator< and operator==). The operator<< below was
also added to facilitate streaming of elements to output (displaying the
elements).
#pragma warning(disable:4786)
#include
#include <algorithm> // for std::copy
#include <iterator> // for std::ostream_iterator
#include <set> // standard container
/* Element class */
template< class T >
class Element
{
T e; // private storage
public:
Element(T t) : e(t) { }
Element(const Element& copy) { e = copy.e; }
~Element() { }
Element<T>& operator=(const Element<T>& rv)
{
if(&rv == this) return *this;
e = rv.e;
return *this;
}
friend std::ostream&
operator<<(std::ostream& os, const Element< T >& t);
friend bool
operator==(const Element< T >& lv, const Element< T >& rv);
friend bool
operator<(const Element< T >& lv, const Element< T >& rv);
};
/* global functions - the friends */
template< class T >
std::ostream&
operator<<(std::ostream& os, const Element< T >& t)
{
os << t.e;
return os;
}
template< class T >
bool
operator==(const Element< T >& lv, const Element< T >& rv)
{
return lv.e == rv.e;
}
template< class T >
bool
operator<(const Element< T >& lv, const Element< T >& rv)
{
return lv.e < rv.e;
}
/* Container class */
template < class T >
class Container
{
std::set< T > elements;
public:
Container() : elements() { }
~Container() { }
void insert(const T& t)
{
elements.insert(t);
}
void erase(const T& t)
{
elements.erase(t);
}
void display() const
{
std::cout << "nContainer ( elements = "
<< elements.size()
<< " )n";
std::copy( elements.begin(),
elements.end(),
std::ostream_iterator< T >(std::cout, " "));
}
};
int main()
{
typedef Element<int> E; // doesn't have to be an integer
Container< E > container; // the manager
for (int i = 0; i < 10; ++i)
{
container.insert(E(i));
}
container.display(); // show container
E e(7); // lets loose the 7
container.erase(e);
container.display(); // show resulting container
return 0;
}
/*
Container ( elements = 10 )
0 1 2 3 4 5 6 7 8 9
Container ( elements = 9 )
0 1 2 3 4 5 6 8 9
*/
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
James Kanze Guest
|
Posted: Sun Oct 16, 2005 4:16 pm Post subject: Re: How to delete yourself??? |
|
|
Gene Bushuyev wrote:
| Quote: | christian.siegl (AT) gmail (DOT) com> wrote in message
news:1129299055.951725.150750 (AT) o13g2000cwo (DOT) googlegroups.com...
[...]
class parent;
class child
{
public:
child();
~child();
parent* pp;
void DeleteMe(void)
{
pp->DeleteChild(this);
}
};
class parent
{
public:
parent();
~parent();
child* ary_c[1000]; // something like that....
void DeleteChild(child *pc)
{
// delete child from the array here and delete its instance....
// however this is done here.... its not important....
}
};
////////////////////////////////////////////////////////////////////////
So the big question is, is this code rubbish or not??? I mean
it works, because I don't touch any member variables from
class child. But is this nice code??? Is there a different way
to handle this problem???
No it's not a nice code Not that it will not work, but the
design is definitely suspicious. The first thing you need to
remember, the class that owns the object is responsible for
its deletion. That is, your "child" objects should never
decide to delete themselves. The algorithm should ask
"parent" object to erase them.
|
If you look closely, you'll see that that is exactly what he is
doing. Which, of course, only obscures the problem.
Supposing that his design is correct, then it would seem that
the child is responsible for its own lifetime. Nothing strange
there; I would be suspicious of a design where this didn't occur
in some classes. If this is the case, however, then *only* the
child should delete itself (using delete this); there should be
no delete in the parent. What I suspect (but he doesn't give
enough information for me to be sure) is that he is passing by
the parent in order to be able to null the pointer to the
child. The classical solution for this is some sort of
notification mechanism, triggered in the destructor.
| Quote: | By the same token, I would subject "parent* child::pp" to
examination. Why would "child" need to know about the
"parent"?
|
So that it can notify it when something happens.
A better solution, of course, would be to use the Observer
pattern; the child still sort of knows about the parent, but it
only knows the parent as an observer, and doesn't really know
any of the details. All of the observers are notified on the
death of an object; why it is important that they know of this
death is their business.
| Quote: | You shouldn't need it. Finally, why not to use a standard or
boost container, that not only creates a cleaner and leaner
code, but will also steer you into the right design decisions.
|
Not a container, but it may be possible to use
boost::shared_ptr, with the parent containing weak_ptr. I
rather suspect that a more general solution would be better,
however; suppose that instead of a C style array, Parent
maintained the pointers in an std::set, with only valid
pointers. In that cas, on notification, the parent would remove
the pointer from the set, rather than nulling it.
--
James Kanze mailto: [email]james.kanze (AT) free (DOT) fr[/email]
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Gene Bushuyev Guest
|
Posted: Sun Oct 16, 2005 11:19 pm Post subject: Re: How to delete yourself??? |
|
|
"James Kanze" <kanze (AT) none (DOT) news.free.fr> wrote
| Quote: | Gene Bushuyev wrote:
[email]christian.siegl (AT) gmail (DOT) com[/email]> wrote in message
news:1129299055.951725.150750 (AT) o13g2000cwo (DOT) googlegroups.com...
[...]
So the big question is, is this code rubbish or not??? I mean
it works, because I don't touch any member variables from
class child. But is this nice code??? Is there a different way
to handle this problem???
No it's not a nice code Not that it will not work, but the
design is definitely suspicious. The first thing you need to
remember, the class that owns the object is responsible for
its deletion. That is, your "child" objects should never
decide to delete themselves. The algorithm should ask
"parent" object to erase them.
If you look closely, you'll see that that is exactly what he is
doing. Which, of course, only obscures the problem.
|
No, that's not what I said. I said the algorithm should be able directly tell
the owner to erase the child; not asking a child to delete itself and
redirecting the request to the owner.
| Quote: |
Supposing that his design is correct, then it would seem that
|
Which is probably not.
| Quote: | the child is responsible for its own lifetime. Nothing strange
there; I would be suspicious of a design where this didn't occur
in some classes. If this is the case, however, then *only* the
|
IMHO it is strange. And we had lengthy discussions already whether "delete this"
is evil and whether it is ever necessary. I always expressed the same oppinion:
"yes" to the former and "no" to the latter. In a nutshell, a simpler code is a
better code, "mentally stable" code is better than suicidal code. Suicidal code
is an unnecessary complication and may harm other innocent code.
| Quote: | child should delete itself (using delete this); there should be
no delete in the parent. What I suspect (but he doesn't give
|
In this case you don't know if the parent is required to do more than just
deleting the child. And the child should have no knowledge about the bookkeeping
the parent may need to do. If that is the case then redirecting erasing request
to the parent is a must, which only exposes the weakness of this design. And as
I mentioned in the beginning, it's never necessary to request a child to commit
suicide, it's always possible to refactor algorithm to directly tell the parent
what to do with the child.
| Quote: | enough information for me to be sure) is that he is passing by
the parent in order to be able to null the pointer to the
child. The classical solution for this is some sort of
notification mechanism, triggered in the destructor.
By the same token, I would subject "parent* child::pp" to
examination. Why would "child" need to know about the
"parent"?
So that it can notify it when something happens.
|
But it doesn't need to notify anybody about anything, it's owened by the parent,
and it's the parent's responsibility to know what each of its children is doing
and notify whoever necessary. The only "notification" the child may need is
throwing an exception when it cannot perform the requested operation.
| Quote: |
A better solution, of course, would be to use the Observer
pattern; the child still sort of knows about the parent, but it
only knows the parent as an observer, and doesn't really know
any of the details. All of the observers are notified on the
death of an object; why it is important that they know of this
death is their business.
|
You don't need an observer on the child because it's owned by the parent. You
can have observers on the parent for all children.
| Quote: |
You shouldn't need it. Finally, why not to use a standard or
boost container, that not only creates a cleaner and leaner
code, but will also steer you into the right design decisions.
Not a container, but it may be possible to use
boost::shared_ptr, with the parent containing weak_ptr. I
rather suspect that a more general solution would be better,
however; suppose that instead of a C style array, Parent
maintained the pointers in an std::set, with only valid
pointers. In that cas, on notification, the parent would remove
the pointer from the set, rather than nulling it.
|
That's not what I meant. I said it would be better to use a container and get
rid of back pointer to the parent altogether.
For example,
class child
{
// provide functions that do what the child can do
// asking noting from the parent
};
class parent
{
std::vector<child> children;
public:
void erase(/*whatever is used to identify the child*/)
{
// do all the necessary bookkeeping, notification, etc.
// and erase the child
children.erase(child_iterator);
// post erase notification, etc.
}
// ...
};
The simpler the design is, the less indirection, the less derivation, the less
dependencies the design has, the better is its quality (in a usual definition of
the words "quality" and "is" :-)
-- Gene
----------------------------------------------------------------
There is no greatness where there is no simplicity, goodness and truth. ~ Leo
Tolstoy
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
hacker++ Guest
|
Posted: Mon Oct 17, 2005 11:21 am Post subject: Re: How to delete yourself??? |
|
|
Gene Bushuyev wrote:
| Quote: |
No, that's not what I said. I said the algorithm should be able directly tell
the owner to erase the child; not asking a child to delete itself and
redirecting the request to the owner.
|
It might not always be the best way. Imagine an event driven system
e.g. a GUI. Imagine that the parent is a window and the child is one of
many dialogs launched by the parent. Some child dialogs have "close"
buttons on them.
The parent reacts to a "launch_dialog" event by creating a new dialog:
void parent::launch_dialog()
{
dialogs.add(new dialog(this)); // dialogs is a container of dialog
pointers.
}
The parent reacts to a "shutdown" event by closing all dialogs
launched:
void parent::shutdown()
{
for_each(dialogs.begin(), dialogs.end(), close_dialog); // pseudo
code - use suitable algorithm + binder
dialogs.clear();
}
close_dialog will eventually delete the dialog from memory.
So far so good. But this isn't the only way dialogs need to be deleted.
Remember the "close" button on the dialog itself?
The child dialog will have registered its own event handling mechanism
wherein it reacts to the "close_button_click" event by
1. notifying the parent that it has been closed. The parent removes it
from the dialogs container.
2. ???? delete this ????
Remember that the parent cannot (rather should not) intercept the
"close_button_click" event as then it would need to know the internals
of the child. (Some child dialogs might not have close buttons at all,
while others might want to close in response to some other event).
I guess that the OP has a situation somewhat like the above.
| Quote: | In this case you don't know if the parent is required to do more than just
deleting the child. And the child should have no knowledge about the bookkeeping
the parent may need to do. If that is the case then redirecting erasing request
to the parent is a must, which only exposes the weakness of this design. And as
I mentioned in the beginning, it's never necessary to request a child to commit
suicide, it's always possible to refactor algorithm to directly tell the parent
what to do with the child.
|
How do we do this in my example without complicating it?
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Kai-Uwe Bux Guest
|
Posted: Mon Oct 17, 2005 2:28 pm Post subject: Re: How to delete yourself??? |
|
|
Gene Bushuyev wrote:
| Quote: | "James Kanze" <kanze (AT) none (DOT) news.free.fr> wrote in message
news:435256eb$0$20201$626a14ce (AT) news (DOT) free.fr...
Gene Bushuyev wrote:
[snip]
the child is responsible for its own lifetime. Nothing strange
there; I would be suspicious of a design where this didn't occur
in some classes. If this is the case, however, then *only* the
IMHO it is strange. And we had lengthy discussions already whether "delete
this" is evil and whether it is ever necessary. I always expressed the
same oppinion: "yes" to the former and "no" to the latter. In a nutshell,
a simpler code is a better code, "mentally stable" code is better than
suicidal code. Suicidal code is an unnecessary complication and may harm
other innocent code.
[snip]
By the same token, I would subject "parent* child::pp" to
examination. Why would "child" need to know about the
"parent"?
So that it can notify it when something happens.
But it doesn't need to notify anybody about anything, it's owened by the
parent, and it's the parent's responsibility to know what each of its
children is doing and notify whoever necessary. The only "notification"
the child may need is throwing an exception when it cannot perform the
requested operation.
|
Why should a child not be responsible for its own lifetime? Think of a
scheduler class (parent) that owns thread objects (children). In this case
the children are clearly acting autonomously and will need to notify the
parent every once in a while about important events. In particular, when a
thread comes to the end of its execution path, it will want to notify the
scheduler that it died and wants to be released into nirvana.
This is not arguing that the best way to deal with this is to say "delete
this", but a child managing its own lifetime is nothing strange at all to
me.
Best
Kai-Uwe Bux
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
christian.siegl@gmail.com Guest
|
Posted: Mon Oct 17, 2005 6:25 pm Post subject: Re: How to delete yourself??? |
|
|
This is exact the problem i have and i wanted to express with my (very
brief) example above. I thought the problem is more general and there
are more general solutions but may be it only appeares on programming a
GUI. So what to do??? Are there appropriate solutions????
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
kanze Guest
|
Posted: Tue Oct 18, 2005 2:36 am Post subject: Re: How to delete yourself??? |
|
|
Gene Bushuyev wrote:
| Quote: | "James Kanze" <kanze (AT) none (DOT) news.free.fr> wrote in message
news:435256eb$0$20201$626a14ce (AT) news (DOT) free.fr...
Gene Bushuyev wrote:
[email]christian.siegl (AT) gmail (DOT) com[/email]> wrote in message
news:1129299055.951725.150750 (AT) o13g2000cwo (DOT) googlegroups.com...
[...]
So the big question is, is this code rubbish or not??? I
mean it works, because I don't touch any member variables
from class child. But is this nice code??? Is there a
different way to handle this problem???
No it's not a nice code Not that it will not work, but
the design is definitely suspicious. The first thing you
need to remember, the class that owns the object is
responsible for its deletion. That is, your "child"
objects should never decide to delete themselves. The
algorithm should ask "parent" object to erase them.
If you look closely, you'll see that that is exactly what he
is doing. Which, of course, only obscures the problem.
No, that's not what I said. I said the algorithm should be
able directly tell the owner to erase the child; not asking a
child to delete itself and redirecting the request to the
owner.
|
What algorithm? The one which child is executing?
| Quote: | Supposing that his design is correct, then it would seem that
Which is probably not.
|
It may be; it may not be. I am assuming that in the posted
code, parent and child are "placeholder" names, which don't
really signify much. And that without knowing anything more
about the application, it's impossible to say whether the design
is correct or not.
| Quote: | the child is responsible for its own lifetime. Nothing
strange there; I would be suspicious of a design where this
didn't occur in some classes. If this is the case, however,
then *only* the
IMHO it is strange. And we had lengthy discussions already
whether "delete this" is evil and whether it is ever
necessary. I always expressed the same oppinion: "yes" to the
former and "no" to the latter.
|
Yes, but you were never able to give any concrete reasons for
your prejudice. OO principles say that the object is
responsible for its own behavior.
| Quote: | In a nutshell, a simpler code is a better code, "mentally
stable" code is better than suicidal code. Suicidal code is
an unnecessary complication and may harm other innocent code.
|
Encapsulation is normally an advantage. Having an object
process events which affect it is a form of encapsulation. If
handling the event should result in the object disappearing,
trying to move the treatment out of the object is only
obfuscation, and will result in unnecessary program
complication.
| Quote: | child should delete itself (using delete this); there should
be no delete in the parent. What I suspect (but he doesn't
give
In this case you don't know if the parent is required to do
more than just deleting the child. And the child should have
no knowledge about the bookkeeping the parent may need to
do.
|
Exactly.
| Quote: | If that is the case then redirecting erasing request to
the parent is a must,
|
Suppose that there are several objects which must do this sort
of bookkeeping. The Observer pattern exists for a reason.
| Quote: | which only exposes the weakness of this design. And as I
mentioned in the beginning, it's never necessary to request a
child to commit suicide, it's always possible to refactor
algorithm to directly tell the parent what to do with the
child.
|
Which is, in sum, what his code does. The problem is that if
the actual decision is made in reaction to an event handled by
the child, such refactorization is just obfuscation. (It's
sometimes necessary, e.g. for reasons involved with transaction
management. But it is always added complication.)
| Quote: | enough information for me to be sure) is that he is passing
by the parent in order to be able to null the pointer to the
child. The classical solution for this is some sort of
notification mechanism, triggered in the destructor.
By the same token, I would subject "parent* child::pp" to
examination. Why would "child" need to know about the
"parent"?
So that it can notify it when something happens.
But it doesn't need to notify anybody about anything, it's
owned by the parent,
|
How do you know that? I think you're reading too much into the
names here. (If there really is a parent child relationship
between the objects, of course, it may be reasonable for the
parent to decide when the child should terminate. Or maybe not;
without knowing the actual situation, it is impossible to be
sure.)
| Quote: | and it's the parent's responsibility to know what each of its
children is doing and notify whoever necessary. The only
"notification" the child may need is throwing an exception
when it cannot perform the requested operation.
|
Life just isn't that simple. If you follow your logic through,
you end up with one class knowing everything about the system.
That's obviously poor design.
Forget the name. Imagine instead that you have a class modeling
some external hardware, say in a network mangager. And other
classes displaying a graphic representation of the current
network state. If the modeling class receives a signal that the
hardware in question has been removed, what should it do?
And more to the point here, how should the classes managing the
graphic representation be informed? Because they have to update
the representation to remove the hardware in question.
| Quote: | A better solution, of course, would be to use the Observer
pattern; the child still sort of knows about the parent, but
it only knows the parent as an observer, and doesn't really
know any of the details. All of the observers are notified
on the death of an object; why it is important that they
know of this death is their business.
You don't need an observer on the child because it's owned by
the parent.
|
You keep saying this, but you provide no justification. What
makes you think that the child is owned by the parent.
| Quote: | You can have observers on the parent for all children.
|
You can introduce another level of indirection, and additional
complexity, yes. What does it buy you?
| Quote: | You shouldn't need it. Finally, why not to use a standard
or boost container, that not only creates a cleaner and
leaner code, but will also steer you into the right design
decisions.
Not a container, but it may be possible to use
boost::shared_ptr, with the parent containing weak_ptr. I
rather suspect that a more general solution would be better,
however; suppose that instead of a C style array, Parent
maintained the pointers in an std::set, with only valid
pointers. In that cas, on notification, the parent would
remove the pointer from the set, rather than nulling it.
That's not what I meant. I said it would be better to use a
container and get rid of back pointer to the parent
altogether.
|
If the child is handling events, and needs to notify the parent,
it needs some sort of means of routing the notification.
Sometimes, a direct pointer is the simplest solution.
Othertimes, you may want some sort of dispatcher. (I've done a
lot of distributed systems, where the "parent" wasn't on the
same machine as the "child". Obviously, in such cases, a normal
C++ pointer is not sufficient.)
| Quote: | For example,
class child
{
// provide functions that do what the child can do
// asking noting from the parent
};
class parent
{
std::vector<child> children;
public:
void erase(/*whatever is used to identify the child*/)
{
// do all the necessary bookkeeping, notification, etc.
// and erase the child
children.erase(child_iterator);
// post erase notification, etc.
}
// ...
};
The simpler the design is, the less indirection, the less
derivation, the less dependencies the design has, the better
is its quality (in a usual definition of the words "quality"
and "is"
|
Certainly. Of course, without knowing what each class' role is
in the total application, it's impossible to say what solution
is the best. Who calls parent::erase here? If the information
concerning the child is contained in child, then it can only be
child, and we have a circular dependancy, which is usually
considered bad.
--
James Kanze GABI Software
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
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Carl Barron Guest
|
Posted: Tue Oct 18, 2005 10:29 am Post subject: Re: How to delete yourself??? |
|
|
<christian.siegl (AT) gmail (DOT) com> wrote:
| Quote: | Hello,
I got a strange problem, which should be quite ordinary but I don't
know how to handle it....
I have got two classes, a parent and a child. The child needs a
function to delete itself.... The question is, whether or not this is
possible....
Asume we have the following code:
//////////////////////////////////////////////////////
class parent;
class child
{
public:
child();
~child();
parent* pp;
void DeleteMe(void)
{
pp->DeleteChild(this);
}
};
class parent
{
public:
parent();
~parent();
child* ary_c[1000]; // something like that....
void DeleteChild(child *pc)
{
// delete child from the array here and delete its instance....
// however this is done here.... its not important....
}
};
////////////////////////////////////////////////////////////////////////
So the big question is, is this code rubbish or not??? I mean it works,
because I don't touch any member variables from class child. But is
this nice code??? Is there a different way to handle this problem???
Thanks very much for any comments....
|
Seems like a job for tr1::weak_ptr and tr1::shared_ptr. Weak_ptr
knows when its an invalid pointer and notifies you with the member
function bool expired() const; it can be used to get another
shared_ptr of its contents with a constructor of shared_ptr and that
shared_ptr can be used to access the data of the child. or
shared_ptr::get() can get a raw pointer to pass to other API's.
Seems its not worth the debugging of a manual delete this and notify
approach, certainly it is less bug prone.
If I see manual delete this and notify code I want a discertation
on why, weak_ptr/shared_ptr does not provide a better approach. It is
certainly more maintainable with weak_ptrs and shared_ptrs.
your parent function becomes simply for exposition
c;ass parent
{
typedef TR1::weak_ptr<child> WeakPtr;
typedef std::vector<WeakPtr> Container;
Container children;
public:
void remove_dead();;
// ...
};
void parent::remove_dead()
{
children.erase
(
std::remove_if
(
childern.begin(),
children.end(),
std::mem_fun(&WeakPtr::expired)
),
children.end()
);
}
void display()
{
remove_dead(); // no more worries about dead ptrs
for_each(children.begin(),children.end(),
do_something());
}
};
where do_something is like
void process_child(child *);
struct do_something
{
void operator () (TR1::weak_ptr<child> x)
{
// allow acces to the child and keep a valid ptr
// at least until block exits.
TR1::shared_ptr<child> p(x);
process_child(p.get());
}
}
see tr1 or boost/smart_ptrs for details on shared_ptr/weak_ptr.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Gene Bushuyev Guest
|
Posted: Tue Oct 18, 2005 10:29 am Post subject: Re: How to delete yourself??? |
|
|
"hacker++" <atul.bhouraskar (AT) gmail (DOT) com> wrote
| Quote: | Gene Bushuyev wrote:
No, that's not what I said. I said the algorithm should be able directly tell
the owner to erase the child; not asking a child to delete itself and
redirecting the request to the owner.
It might not always be the best way. Imagine an event driven system
e.g. a GUI. Imagine that the parent is a window and the child is one of
many dialogs launched by the parent. Some child dialogs have "close"
buttons on them.
[...]
The child dialog will have registered its own event handling mechanism
wherein it reacts to the "close_button_click" event by
1. notifying the parent that it has been closed. The parent removes it
from the dialogs container.
2. ???? delete this ????
[...] |
First of all, let me clarify some words used in this discussion. The words
parent and child are unfortunate in the original post. The subject we were
discussing is ownership (creating and destroying). In GUI design (and in your
example) parent and child refer to location of window controls and message flow.
The latter may have different shapes and forms. In fact I don't think your
option #1 is good enough for two reasons: because it requires the child to know
too much about parent, and because immediate message notification introduces a
tight coupling. It would be more flexible to send the message to the top level
message loop from where at the proper time it could be routed to the correct
handler or dispatched to a common sink if there is none.
Returning to our ownership discussion, here are my three most important rules:
simplicity, simplicity, and simplicity. The "parent" in this code created and
owns the "child" objects, and therefore, it is responsible for their lifetime.
Period. An owned object should not control its owner, the owner controls it's
objects. The less the owned object knows about the owner, the better. In
general, having simple and straight control paths from owners to owned objects
makes a better quality design. Control cycles and upstream control paths produce
tighter coupling, which hurt scalability, maintainability, testability, ... and
all other -ilities. If an upstream control is needed (like in your GUI example)
it should be done through a weak coupling, like a message mechanism that has
minimal knowledge of the upstream objects.
-- Gene
----------------------------------------------------------------
There is no greatness where there is no simplicity, goodness and truth. ~ Leo
Tolstoy
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Gene Bushuyev Guest
|
Posted: Tue Oct 18, 2005 10:30 am Post subject: Re: How to delete yourself??? |
|
|
"Kai-Uwe Bux" <jkherciueh (AT) gmx (DOT) net> wrote
[...]
| Quote: |
Why should a child not be responsible for its own lifetime? Think of a
|
Because it's an important design rule: what you create, also destroy; and don't
destroy what doesn't belong to you. Child didn't create itself, it has no
business destroying itself.
-- Gene
----------------------------------------------------------------
There is no greatness where there is no simplicity, goodness and truth. ~ Leo
Tolstoy
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|