我有一个父母"管理几个孩子的生命周期的对象"对象。对象执行一些操作,在完成后,它们向其父级(通过回调)发出信号,告知它们已完成并且可以被销毁。
玩具示例:
#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();
}
问题在于,在调用自己的方法时有效地摧毁了一个孩子,这当然不是一个好主意。做这样的事情有没有模式?
答案 0 :(得分:3)
只要Child
在on_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()
,以便之前完成的子项在信号被添加到已完成的列表之前被清除。当然,您可以允许从外部触发清理。这些都不是彼此排斥的。