0

我用 SWIG 在 python 中包装了一个 C++ 类和一个 C++ 函数。

class Module { ... };
void register_module(Module *m);

函数 register_module() 将给定的模块放在一个全局列表中,以便从那时起 C++ 代码持有一个指向该模块的指针,并使用它。

现在,从嵌入式 python 解释器运行的以下 python 代码崩溃

>>> register_module(Module())

另一方面,以下 python 代码不会崩溃

>>> m = Module()
>>> register_module(m)

显然,原因是在第一种情况下,对象是由 python 收集的垃圾,而在第二种情况下则不是。

防止python删除在第一种情况下创建并由C++代码使用的匿名对象的最佳方法是什么?

有没有办法在 register_module() 函数中获取关联的 python 代理对象,然后增加其引用计数?

(我知道如果所讨论的类可以交叉转换为 Swig::Director 类,这是可能的,但是假设我们有一个在 python 中定义的 Module 子类的实例,这里不是这种情况) .

4

1 回答 1

1

解决方案。
第 1 步:向 Module 类添加一个成员,以及两个方法。

class Module {
public:
    PyObject *obj;
    void incref() { Py_INCREF(obj); }
    void decref() { Py_DECREF(obj); }
    ...
};

第 2 步:增加 register_module() 中的引用计数。

void register_module(Module *m) {
    m->incref();
    ...
}

(不要忘记在某处减少它)

第 3 步:每当从 Python 构造一个 Module 对象时,破解 SWIG 生成的包装器以将 obj 成员设置为 PyObject 包装器。

在 SWIG 生成的文件 ModulePYTHON_wrap.cxx 中,找到:

SWIGINTERN PyObject *_wrap_new_Module(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
  PyObject *resultobj = 0;
  ...
  Module *result = 0 ;
  ...
  if ( arg1 != Py_None ) {
    /* subclassed */
    result = (Module *)new SwigDirector_Module(arg1);
  } else {
    result = (Module *)new Module();
  }

  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_Module, SWIG_POINTER_NEW |  0 );
  return resultobj;
  ...
}

在我们获得result->obj =之前插入:resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_Module, SWIG_POINTER_NEW | 0 );

  result->obj = resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_Module, SWIG_POINTER_NEW |  0 );

第 4 步:指示 SWIG 在生成的包装器中自动实施修复。

在接口文件中添加以下类型映射声明。

%typemap(out) Module* {
   result->obj = $result = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_Module, SWIG_POINTER_NEW |  0 );
}

这有效地覆盖了默认生成的用于包装新模块对象的代码。

于 2013-03-26T00:11:49.793 回答