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

Dik*_*rAz 10 c++ python api

在我的程序中,我在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;
};
Run Code Online (Sandbox Code Playgroud)

我使用intrusive_ptr来保存从Referenced派生的对象.这使我可以轻松地在C++中保持对所需python对象的引用,并在必要时访问它们.但是当我要从C++中删除python对象时,我的程序崩溃(仅在windows howewer中),即当我调用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 = %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);
}
Run Code Online (Sandbox Code Playgroud)

和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()
Run Code Online (Sandbox Code Playgroud)

示例在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
Run Code Online (Sandbox Code Playgroud)

Use*_*ess 1

这种方法可以吗?

基本上,但是...

  • 我没有看到任何保证add_ref/remove_ref被调用正确的次数(使用 RAII 会自动执行此操作 - 也许这就是您的 intrusive_ptr 所做的?)
  • 如果你尝试remove_ref太多次,我不确定Python能保证什么。如果你selfptr = NULL在知道引用计数从 1 -> 0 时进行设置,你可以捕捉到这个
    • 要么通过硬崩溃,要么通过显式检查,或者通过使用Py_XDECREF
    • 更好的是,只需Py_CLEAR使用

最后......您有任何故障转储或诊断信息吗?