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,那么您不必更改其中的任何内容,因为这两个模块都是从同一堆分配/取消分配的。这个解决方案与我的帖子中的陈述不符。