How to destroy an object in your callback

I have a "parent" object that manages the lifetime of multiple "child" objects. Objects do some things, and after they are done, they signal their parents (via a callback) that they are done and can be destroyed.

Example with a toy:

#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, in fact, the child is destroyed when its own method is called, which is of course not a good idea. Is there a pattern for such things?

+3


source to share


2 answers


As long as it Child

does not have access to any of its own data members after exiting on_done()

, then it is safe for on_done()

before delete

child. It's like a reference-counted object when its reference count drops to 0 - the object's method Release()

still works when called delete this

, but that's ok because it Release()

doesn't have access to any data items after being called delete

.



If you really want to make it safe, you can add reference counting to your class Child

. When Parent

adding a child to your list, increment the child link count. When Parent

removes a child from its list, decrement the child link count. When Child

called on_done()

, it can first increase its own reference count and then decrease the reference count after exiting on_done()

. When the count reaches 0, Child

maybe delete

. Thus, Child

decides when it is safe to free itself from memory, but still allows Parent

control over the list of children.

+3


source


Your parent class bears significant resemblance to a garbage collector, at least in the toy example. GCs usually work by periodically identifying and disposing of garbage; they usually do not clean up objects immediately after they become garbage.



Your code could do the same: the parent on_done()

could move the specified child into a list of disposable children (garbage), which would later clear up any signal. A signal can be embedded create_child()

so that all ready children are cleared before a new child is created. It can also be placed in on_done()

so that previously finished children are cleared before the signals are added to the ready list. And of course you can enable the cleaning to start outside. None of them are mutually exclusive.

+2


source







All Articles