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

C++ 重载delete运算符以删除库中分配的内容,c++,c++11,shared-libraries,C++,C++11,Shared Libraries,我使用的框架有一个类寄存器,我可以在其中注册一个类的实例 Register r; A * a1 = new A(); r->register(a1); A * a2 = new A(); r->register(a2); 当超出范围时,Register将拥有所有权并删除所有已注册的As 我想在共享库中修改As的行为(在我的例子中是这样的),所以,我要这样做(在库中): 然后在主程序中 Register r; A * a1 = get_customized_a(); r->re

我使用的框架有一个类寄存器,我可以在其中注册一个类的实例

Register r;
A * a1 = new A();
r->register(a1);
A * a2 = new A();
r->register(a2);
当超出范围时,Register将拥有所有权并删除所有已注册的
A
s

我想在共享库中修改
A
s的行为(在我的例子中是这样的),所以,我要这样做(在库中):

然后在主程序中

Register r;
A * a1 = get_customized_a();
r->register(a1);
但是现在
a1
将在主程序中删除,而不是在库中删除!我的替补是个大禁忌

那么如何解决这个问题呢


我提出了两个解决方案:

1) 使用并通过独立功能对其进行自定义

在插件中:

void customize_a(A * a) { ... }
在主程序中:

Register r;
A * a1 = new A();
customize_a(a1);
r->register(a1);
Register r;
A * a1 = get_customized_a();
r->register(a1);
我必须说我不太喜欢它:/

2) 类B的重载删除运算符

插件中

class B : public A {
    ...
    static void operator delete(void * ptr) {
        ::operator delete(ptr);
    }
}
在主程序中:

Register r;
A * a1 = new A();
customize_a(a1);
r->register(a1);
Register r;
A * a1 = get_customized_a();
r->register(a1);
但是,我以前从未重载过
操作符delete
,因此我不确定这是否会起作用(如预期的那样)

3) 有什么方法我错过了吗?有更好的解决办法吗


谢谢大家。

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

另一方面,如果对象的构造和销毁发生在不同的模块中,那么只有当这些模块的new和delete操作符从不同的池分配/释放内存时,这才是一个问题。例如,如果这些模块针对运行库的不同版本进行链接,则可能出现这种情况。类似的情况是,您显式重写库中的new和delete运算符,自己从不同的池进行分配,而这些模块的分配器代码之间不进行协作。在这种情况下,虚拟析构函数不会使您免于这些问题,因为对象的构造使用一个模块的分配器/池分配内存,而您调用另一个模块的delete操作符,该模块尝试从完全不同的池中解除分配对象。结果通常是错误的“堆损坏”运行时错误或类似的错误


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

A
是否具有虚拟dtor?另外,您在哪个平台上?不,如果我正确阅读源代码,
A
没有虚拟dtor。平台是Linux,AMD64如果是Linux,您真的不必特别注意模块边界。在没有虚拟数据的基础类型中删除,或者保持UB状态。所以。。。在linux上,我可以安全地在主程序中删除共享库中分配的内容吗?在实践中,这是一种有效的行为,还是始终有效?以及如何处理虚拟dtor的缺失/这对我没什么帮助。我不能改变对象保持(=无法切换到智能指针)或删除(=无法通过
Release()
)强制删除的方式,我无法控制该代码。@Paladin我写这个答案只是为了澄清问题。你的问题有很多很好的解决方案,我的帖子并没有将问题缩小到一个单一的黄金模式。如果您的基类包含一个虚拟dtor,那么您不必更改其中的任何内容,因为这两个模块都是从同一堆分配/取消分配的。这个解决方案与我的帖子中的陈述不符。