我的程序在C++中管理对Python对象的引用。也就是说,我所有的类都派生自Referenced类,该类包含指向相应Python对象的指针。
class Referenced
{
public:
unsigned use_count() const
{
return selfptr->ob_refcnt;
}
void add_ref() const
{
Py_INCREF(selfptr);
}
void remove_ref() const
{
Py_DECREF(selfptr);
}
PyObject* selfptr;
};
我使用intrusive_ptr来持有从Referenced派生的对象。这使得我可以轻松地在C++中保留对所需Python对象的引用,并在必要时访问它们。但是,当从C++中删除Python对象时(即当我调用Py_DECREF(selfptr)时),我的程序会崩溃(仅在Windows上发生),即使selfptr->ob_refcnt == 1。
这种方法可行吗?更新:我最终找到了程序中的问题。它与对象删除无直接关系。为了检查最初的问题,我实现了一个简单的扩展模块,记住对Python对象的引用,并在需要时释放它。这是它:
#include <Python.h>
static PyObject* myObj;
static PyObject* acquirePythonObject(PyObject* self, PyObject* obj)
{
printf("trying to acquire python object %p, refcount = %d\n", obj, obj->ob_refcnt);
myObj = obj;
Py_INCREF(myObj);
printf("reference acquired\n");
return Py_True;
}
static PyObject* freePythonObject(PyObject*, PyObject*)
{
printf("trying to free python object %p, refcount = %d\n", myObj, myObj->ob_refcnt);
Py_DECREF(myObj);
printf("reference removed\n");
return Py_True;
}
static PyMethodDef moduleMethods[] =
{
{"acquirePythonObject", acquirePythonObject, METH_O, "hold reference to python object."},
{"freePythonObject", freePythonObject, METH_NOARGS, "free reference to python object."},
{NULL, NULL, 0, NULL}
};
PyMODINIT_FUNC initmodule(void)
{
Py_InitModule("module", moduleMethods);
}
和Python脚本:
import module
class Foo:
def __init__(self):
print "Foo is created"
def __deinit__(self):
print "Foo is destroyed"
def acquireFoo():
foo = Foo()
module.acquirePythonObject(foo)
def freeFoo():
module.freePythonObject()
if __name__ == "__main__":
acquireFoo()
freeFoo()
样例在Windows和Linux系统下无缝运行。以下是输出结果。
Foo is created
trying to acquire python object 0x7fa19fbefd40, refcount = 2
reference acquired
trying to free python object 0x7fa19fbefd40, refcount = 1
Foo is destoryed
reference removed
PyTypeObject
结构中的指针定义。如果它们都指向同一个DLL,那么就不应该有问题。(如果链接正确,也不应该有问题。) - James Kanzefree
函数。但当然,Python 不会直接调用free
函数;它会调用为该类型指定的释放函数。这将始终指向同一函数,在同一 DLL 中。 - James Kanze