考虑以下类结构:
class Filter
{
virtual void filter() = 0;
virtual ~Filter() { }
};
class FilterChain : public Filter
{
FilterChain(collection<Filter*> filters)
{
// copies "filters" to some internal list
// (the pointers are copied, not the filters themselves)
}
~FilterChain()
{
// What do I do here?
}
void filter()
{
// execute filters in sequence
}
};
我在库中暴露了这个类,所以我无法控制它的使用方式。
我目前有一些关于Filter
对象FilterChain
的所有权的设计问题正在抓住指针。更具体地说,以下是FilterChain
的两种可能的使用方案:
FilterChain
对象。例如,这些函数之一构造了一个文件的过滤器链,它可以描述任意复杂的过滤器(包括过滤器链的过滤器链等)。一旦完成作业,该功能的用户负责对象销毁。Filter
个对象,并希望以特定方式将它们组合在过滤器链中。用户构造FilterChain
个对象供自己使用,然后在完成后将其销毁。当引用它们的Filter
被销毁时,FilterChain
个对象不得被销毁。现在,管理FilterChain
对象所有权的两种最简单的方法是:
FilterChain
拥有Filter
个对象。这意味着FilterChain
引用的对象在FilterChain
的析构函数中被销毁。这与方案B不兼容。FilterChain
不拥有Filter
个对象。这意味着FilterChain
的析构函数什么都不做。现在方案A存在问题,因为用户必须知道所涉及的所有Filter
个对象的内部结构,以便在不丢失所有对象的情况下将其全部销毁,因为父FilterChain
不做它本身。这只是糟糕的设计,并要求内存泄漏。因此,我需要更复杂的东西。我的第一个猜测是设计一个带有可设置布尔标志的智能指针,指示智能指针是否拥有该对象。然后,Filter
不会收集指向FilterChain
个对象的指针集合,而是会收集到Filter
个对象的智能指针集合。当调用FilterChain
的析构函数时,它会破坏智能指针。然后智能指针本身的析构函数会破坏被指向的对象(Filter
对象)当且仅当指示所有权的布尔标志被设置时。
我觉得这个问题在C ++中很常见,但我的网络搜索流行的解决方案或聪明的设计模式并不是很成功。确实,auto_ptr
在这里并没有真正的帮助,shared_ptr
似乎有点矫枉过正。那么,我的解决方案是否是一个好主意?
答案 0 :(得分:2)
过滤器是否过大,以至于在创建FilterChain
时,您无法简单地为每个过滤器制作一份深层副本?如果你能够做到这一点,那么你所有的问题都会消失:FilterChain
总是会自行清理。
如果由于内存问题而不是选项,那么使用shared_ptr
似乎最有意义。调用者必须负责为其关注的每个对象保留shared_ptr
,然后FilterChain
将知道在delete
d时是否删除特定过滤器。
编辑:正如Neil所说,Filter
需要一个虚拟析构函数。
答案 1 :(得分:2)
这里的智能指针并不过分:显然你有一个设计问题,不管怎样都需要仔细考虑对象的生命周期和所有权。如果您希望能够在运行时重新修补过滤器图形中的过滤器,或者能够创建复合FilterChain
对象,则尤其如此。
使用shared_ptr
将一举消除大部分问题,使您的设计更加简单。我认为唯一可能的问题是你的过滤器是否恰好包含循环。我可以看到,如果您有某种反馈循环,可能会发生这种情况。在那个例子中,我建议让一个类拥有所有Filter
个对象,然后FilterChain
将存储指向Filter
个对象的弱指针。
我打赌过滤阶段的执行时间远远超过解除引用智能指针的额外开销。 shared_ptr
的设计非常轻巧。
答案 2 :(得分:0)
FilterChain
应该有一个单独的DeleteAll()
方法,该方法对集合进行迭代,并delete
为过滤器。在场景A中调用 ,在场景B中调用 。这确实需要FilterChain用户的一些情报,但不能再记住{{ 1}}并反对他们delete
'd。 (他们应该能够处理,或者他们应该得到记忆泄漏)
答案 3 :(得分:0)
我会使用FilterChain不拥有Filter对象。然后,在您的库中,当您需要从文件加载FilterChain时,您将拥有另一个Loader对象,该对象负责Filter对象的生命周期。因此,FilterChain将为库和用户创建的链加载的链一致地工作。