我的gui应用程序支持多态定时事件,这意味着用户调用new,gui调用delete。如果运行时不兼容,这可能会产生问题。
所以我被告知建议的解决方案是:
class base;
class Deallocator {
void operator()(base* ptr)
{
delete ptr;
}
}
class base {
public:
base(Deallocator dealloc)
{
m_deleteFunc = dealloc;
}
~base()
{
m_deleteFunc(this);
}
private:
Deallocator m_deleteFunc;
}
int main
{
Deallocator deletefunc;
base baseObj(deletefunc);
}
虽然这是一个很好的解决方案,但它确实要求用户创建一个我不想要的Deallocator对象。然而,我想知道我是否为每个派生类提供了一个Deallocator:例如
class derived : public base
{
Deallocator dealloc;
public:
Derived() : base(dealloc);
{
}
};
我认为这仍然不起作用。约束是: addTimedEvent()函数是Widget类的一部分,它也在dll中,但它由用户实例化。另一个约束是从Widget派生的一些类用它们自己的定时事件类调用这个函数。
鉴于“谁打电话给新人必须打电话给删除”这些限制可以起作用什么呢?
由于
答案 0 :(得分:1)
我建议您研究COM引用计数范例(AddRef和Release)。这允许更灵活的生命周期并保证使用正确的解除分配器,因为对象会自行删除。
请注意,如果您跨越DLL边界共享类对象,那么使用相同的分配器可能会遇到更大的问题。整个单定义规则需要考虑,调用约定,数据布局和名称修改方案在编译器之间有所不同。因此,如果你想要一个可重用的库,你真的需要采用COM方式做事,包括引用计数,自我删除和只包含纯虚函数的接口。无论您是构建真正的COM对象还是您自己的类COM系统,都将取决于您的其他要求。
答案 1 :(得分:0)
首先想到的是给基类一个虚拟(抽象?)SelfDestruct
方法。假设你的DLL的消费者传递了他自己派生的类,他将知道如何解除分配它。
如果他能够通过你所写的课程,那么你就会遇到更多问题。我建议不要分配这样的类,并提供一个静态方法来用你自己的分配器来分配它们。
我不确定我是否已经非常清楚地解释了我的想法......如果没有,请问,我稍后会提供代码。
答案 2 :(得分:0)
可以使用给定约束的是将删除函数指针与每个TimedEvent相关联,其中两者都被指定为addTimedEvent
的参数。
为了减轻客户端创建自定义删除函数的负担,您可以在窗口小部件类的标题中提供内联删除函数作为匿名命名空间的成员。
例如:
// Widget header
class base;
namespace {
inline void default_deleter(base* p)
{
delete p;
}
}
class Widget
{
public:
addTimedEvent(base* event, void(*deleter)(base*));
};
内联函数的优点是它将在客户端代码的上下文中编译,因此delete
也将使用兼容的deallocator作为用于分配事件的客户端。
编辑:将删除功能设为匿名命名空间的成员。这是避免ODR违规所必需的
如果没有命名空间,您将获得两个具有相同外部名称的函数default_deleter
(因此它们与链接器相同),但具有不同的语义,因为它们引用了不同的解除分配器。
使用匿名名称空间,default_deleter
的所有实例都成为链接器的独立实体。这具有(不幸的)副作用,您不能再将该函数用作addTimedEvent
的默认参数。