我使用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子类的实例,这不是案例)。
答案 0 :(得分: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声明。
%typemap(out) Module* {
result->obj = $result = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_Module, SWIG_POINTER_NEW | 0 );
}
这有效地覆盖了默认生成的用于包装新Module对象的代码。