如何在自己的回调中销毁一个对象

时间:2014-12-04 20:50:34

标签: c++

我有一个父母"管理几个孩子的生命周期的对象"对象。对象执行一些操作,在完成后,它们向其父级(通过回调)发出信号,告知它们已完成并且可以被销毁。

玩具示例:

#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();
}

问题在于,在调用自己的方法时有效地摧毁了一个孩子,这当然不是一个好主意。做这样的事情有没有模式?

2 个答案:

答案 0 :(得分:3)

只要Childon_done()退出后on_done()无法访问任何自己的数据成员,那么delete Release()子对象是安全的。它类似于引用计数对象,当引用计数降为0时释放自身 - 当调用delete this时,对象的Release()方法仍在运行,但这是正常的,因为delete没有在致电Child后访问任何数据成员。

如果您真的想要保证安全,可以在Parent课程中添加引用计数。当Parent将子项添加到其列表中时,递增子项的引用计数。当Child从其列表中删除子项时,减少子项的引用计数。当on_done()调用on_done()时,它可以先增加自己的引用计数,然后在Child退出后减少引用计数。当引用计数达到0时,delete可以Child本身。这样,Parent决定何时从内存中释放自己是安全的,同时仍允许{{1}}管理子列表。

答案 1 :(得分:2)

您的父类与垃圾收集器有相似之处,至少在玩具示例中如此。 GC通常通过定期识别和处理垃圾来工作;他们通常不会在物品变成垃圾后立即清理它们。

您的代码可以执行相同的操作:父级on_done()可以将指定的子对象移动到一次性子级列表(垃圾),稍后将清除某些信号。信号可以内置到create_child(),以便在创建新子项之前清除任何已完成的子项。它也可以放入on_done(),以便之前完成的子项在信号被添加到已完成的列表之前被清除。当然,您可以允许从外部触发清理。这些都不是彼此排斥的。