是否可以从c++中删除python中分配的对象?

Is it ok to delete object allocated in python from c++?

本文关键字:分配 对象 python 删除 c++ 是否      更新时间:2023-10-16

在我的程序中,我用c++管理对python对象的引用。也就是说,我所有的类都派生自类reference,它包含指向相应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来保存从reference派生的对象。这使我可以轻松地在c++中保存对所需python对象的引用,并在必要时访问它们。但是当python对象将从c++中删除时,我的程序崩溃(仅在windows中),即当我调用Py_DECREF(selfptr)时,selfptr->ob_refcnt == 1。这个方法可以吗?


Upd:我终于找出了程序中的问题。这与物体移除没有直接关系。为了检查最初的问题,我实现了简单的扩展模块,记住对python对象的引用并根据需要释放它。

#include <Python.h>
static PyObject* myObj;
static PyObject* acquirePythonObject(PyObject* self, PyObject* obj)
{
    printf("trying to acquire python object %p, refcount = %dn", obj, obj->ob_refcnt);
    myObj = obj;
    Py_INCREF(myObj);
    printf("reference acquiredn");
    return Py_True;
}
static PyObject* freePythonObject(PyObject*, PyObject*)
{
    printf("trying to free python object %p, refcount = %dn", myObj, myObj->ob_refcnt);
    Py_DECREF(myObj);
    printf("reference removedn");
    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

这个方法可以吗?

基本上,但是…

  • 我没有看到任何保证add_ref/remove_ref被调用正确的次数(使用RAII将自动执行此操作-也许这就是你的intrusive_ptr所做的?)
  • 如果你尝试remove_ref太多次,我不确定Python保证什么。如果您在知道计数从1到> 0的情况下设置selfptr = NULL,您可能会发现这个问题
    • 要么硬崩溃,要么显式检查,要么使用Py_XDECREF
    • 更好,用Py_CLEAR代替

最后……你有任何崩溃转储或诊断信息吗?