重载delete运算符以删除库中分配的内容

时间:2014-10-04 18:48:26

标签: c++ c++11 shared-libraries

我正在使用具有类Register的框架,我可以在其中注册A的实例。

Register r;
A * a1 = new A();
r->register(a1);
A * a2 = new A();
r->register(a2);

注册将获得所有权,并在超出范围时删除所有已注册的A

我想修改共享库中的A行为(在我的情况下是.so),所以,我会做这样的事情(在库中):

class B : public A {
    ...
}

B * get_customized_a() {
    return new B();
}

然后在主程序中

Register r;
A * a1 = get_customized_a();
r->register(a1);

但现在a1将在主程序中删除,而不是在库中删除!我认为这是一个很大的禁忌。

那么如何解决这个问题?


我想出了两个解决方案:

1)使用A并通过独立功能

进行自定义 插件中的

void customize_a(A * a) { ... }

在主程序中:

Register r;
A * a1 = new A();
customize_a(a1);
r->register(a1);

我必须说我不喜欢它:/

2)B类的重载删除操作符

插件中的

class B : public A {
    ...
    static void operator delete(void * ptr) {
        ::operator delete(ptr);
    }
}

在主程序中:

Register r;
A * a1 = get_customized_a();
r->register(a1);

但是,我之前从未超载operator delete所以我不确定这是否会起作用(按预期)。

3)我错过了任何方法吗?有更好的解决方案吗?

谢谢大家。

1 个答案:

答案 0 :(得分:0)

如果使用指向其中一个基类的指针删除类,则无论对象创建和销毁的位置如何,析构函数都必须在基类中是虚拟的。模块边界与此无关。

另一方面,如果对象的构造和销毁发生在不同的模块中,那么只有当这些模块的new和delete运算符从不同的池分配/释放内存时才会出现问题。例如,如果这些模块链接到运行时库的不同版本,则可能就是这种情况。类似的情况是当您显式覆盖库中的new和delete运算符并自己从不同的池执行分配时,这些模块的分配器代码之间没有合作。在这种情况下,虚拟析构函数不会使您免于出现问题,因为对象的构造使用一个模块的分配器/池分配内存,并且您调用另一个模块的delete运算符,该模块尝试从对象释放对象完全不同的游泳池结果通常是错误的"堆腐败"运行时错误或类似的东西。

如果您遇到上述问题,那么正确的解决方案是在基类中引入虚拟析构函数和虚拟Release()方法。 Release()方法应该删除带有丑陋delete this;的对象。当您将构造的对象传递给外部模块时,它必须通过调用Release()方法而不是直接删除它来删除该对象,这样Release()方法使用删除操作符删除该对象。拥有类和实例的模块。通常这种技术与智能指针相结合,以便外部模块使用智能指针引用这些对象,通过调用Release()方法自动删除对象。