【问题标题】:Overloading delete operator to delete something allocated in library重载删除运算符以删除库中分配的内容
【发布时间】:2014-10-04 18:48:25
【问题描述】:

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

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

Register 将取得所有权并在超出范围时删除所有已注册的As。

我想修改As 在共享库中的行为(在我的例子中是.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) 有没有我错过的方法?有没有更好的解决方案?

谢谢大家。

【问题讨论】:

  • A 有虚拟 dtor 吗?另外,你在哪个平台上?
  • 不,如果我正确读取源代码,A 没有虚拟 dtor。平台是Linux,AMD64
  • 如果是 Linux,你真的不需要特别关心模块边界。但是,通过没有虚拟 dtor 的基本类型删除仍然是 UB。
  • Sooo... 在 linux 上我可以安全地在主程序中删除共享库中分配的内容?这种在实践中有效的行为,还是一直有效?
  • 还有任何想法如何处理虚拟 dtor 的缺失? ://

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


【解决方案1】:

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

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

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

【讨论】:

  • 这对我没有帮助。我无法更改对象的保存方式(== 无法切换到智能指针)或删除(== 无法通过Release() 强制删除),我无法控制该代码。
  • @Paladin 我写这个答案只是为了澄清事情。您的问题有很多很好的解决方案,我的帖子并没有将路径缩小为单一的黄金模式。如果您的基类包含一个虚拟 dtor,那么您不必更改其中的任何内容,因为这两个模块都从同一个堆中分配/解除分配。该解决方案与我帖子中的陈述不符。
猜你喜欢
  • 1970-01-01
  • 2022-11-18
  • 2012-11-18
  • 1970-01-01
  • 1970-01-01
  • 2021-09-05
  • 2014-09-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多