Reputation: 2282
I have a "parent" object that manages the lifetime of several "child" objects. The objects do some stuff and after they are done, they signal to its parent (via a callback) that they are done and can be destroyed.
A toy example:
#include <list>
class Child;
class IChildListener
{
public:
virtual void on_done(Child *child) = 0;
};
class Child
{
public:
Child(IChildListener *parent)
: m_parent(parent)
{
}
void do_stuff()
{
m_parent->on_done(this);
}
protected:
IChildListener *m_parent;
};
class Parent : public IChildListener
{
public:
void on_done(Child* child) {
m_children.remove(child);
delete child;
}
Child *create_child() {
Child* child = new Child(this);
m_children.push_back(child);
return child;
}
protected:
std::list<Child*> m_children;
};
int main(int argc, char** argv) {
Parent p;
Child *c = p.create_child();
c->do_stuff();
}
The problem is that, effectively a child is destroyed during a call of its own method and that's certainly not a good idea. Is there a pattern for doing such things?
Upvotes: 4
Views: 1327
Reputation: 596397
As long as Child
does not access any of its own data members after on_done()
exits, then it is safe for on_done()
to delete
the child object. It is similar to a reference-counted object freeing itself when its reference count falls to 0 - the object's Release()
method is still running when delete this
is called, but that is OK because Release()
doesn't access any data members after calling delete
.
If you really wanted to make this safe, you could add reference counting to your Child
class. When Parent
adds a child to its list, increment the child's reference count. When Parent
removes a child from its list, decrement the child's reference count. When Child
is calling on_done()
, it can increment its own reference count first, and then decrement the reference count after on_done()
exits. When the reference count hits 0, Child
can delete
itself. This way, Child
decides when it is safe to free itself from memory, while still allowing Parent
to manage a list of children.
Upvotes: 4
Reputation: 180286
Your parent class has a considerable resemblance to a garbage collector, at least in the toy example. GCs usually work by periodically identifying and disposing of garbage; they don't usually clean up objects immediately upon them becoming garbage.
Your code could do the same: the parent's on_done()
could move the specified child object to a list of disposable children (garbage), which it will later clean up on some signal. The signal could be built in to create_child()
, so that any finished children are cleaned up before the new child is created. It could also be put into on_done()
so that previously finished children are cleaned up before the one that signals is added to the list of finished ones. And of course you can allow the cleanup to be triggered externally. None of those are exclusive of each other.
Upvotes: 2