首页 > 解决方案 > cppyy 模板类实例化没有虚拟析构函数

问题描述

我在 Python 代码中设置了以下子类:

class NodeRewriter(SyntaxRewriter[SyntaxNode]):
   
   def visit(self, node: SyntaxNode):
      print(node)

以下是相关对象:

RuntimeWarning: class "slang::SyntaxRewriter<slang::SyntaxNode>" has no virtual destructor
  class NodeRewriter(SyntaxRewriter[SyntaxNode]):
>>> print(SyntaxRewriter)
<cppyy.Template 'slang::SyntaxRewriter' object at 0x7fb76c0c15b0>
>>> print(SyntaxNode)
<class cppyy.gbl.slang.SyntaxNode at 0x55e4302f07c0>
>>> print(SyntaxRewriter[SyntaxNode])
<class cppyy.gbl.slang.SyntaxRewriter<slang::SyntaxNode> at 0x55e4308df4b0>
>>> 

我所做的只是创建类,我还没有从中创建任何对象。当我导入包含类和其余 cppyy 代码的文件时,我收到警告。

我需要自己添加__destruct__()方法吗?似乎警告不是指我的子类,而是指它继承的模板实例化。

标签: pythoncppyy

解决方案


在没有看到SyntaxRewriter...的来源的情况下

如果 C++ 中的类没有虚拟析构函数,它通常不适合作为基类,因为如果delete在基类指针上调用,则只会调用基类的析构函数,而不是底层的实际派生类之一指针。有时这没关系,有时您会遇到资源泄漏,有时您会遇到虚假崩溃。

如果一切都在 C++ 中完成,那么当你这样做时它会更加明确,只要你从不这样做就可以了delete这样的基类指针。代码是明确的,你可以小心不要这样做。但是在交叉派生中,在 C++ 基类和 Python 派生类之间存在一个存根(stub)可能并不明显,既可以调解调用也可以管理内存。因此,该存根和实际删除都被隐藏了。此外,交叉派生最常见的用例是将派生的 Python 类的实例发送到 C++ 领域,在那里它们可能会被管理。然后,如果 C++ 在某个时候清理了对象,而没有 C++ 基础的虚拟析构函数,则不会调用存根的析构函数,并且 Python 部分会泄漏(它的引用计数太多而永远不会被清除)。如果 Python 管理对象,这只是一个警告 b/c,即使没有虚拟析构函数也不会泄漏。

实现 a__destruct__不会有任何影响(在任何情况下都不应该这样做;__del__如果需要资源清理,请改用),因为问题(如果有)是由先前编译的 C++ 引起的,并且事后无法更改.

(请注意,可以抑制 Python 警告,请参阅https://docs.python.org/3/library/warnings.html。)


推荐阅读