销毁PyCapsule对象

时间:2016-09-03 09:18:16

标签: python c cpython

根据documentationPyCapsule_New()的第三个参数可以指定一个析构函数,我假设在销毁这个集合时应该调用它。

void mapDestroy(PyObject *capsule) {

    lash_map_simple_t *map;
    fprintf(stderr, "Entered destructor\n");
    map = (lash_map_simple_t*)PyCapsule_GetPointer(capsule, "MAP_C_API");
    if (map == NULL)
         return;
    fprintf(stderr, "Destroying map %p\n", map);
    lashMapSimpleFree(map);
    free(map);

}

static PyObject * mapSimpleInit_func(PyObject *self, PyObject *args) {

    unsigned int w;
    unsigned int h;
    PyObject *pymap;

    lash_map_simple_t *map = (lash_map_simple_t*)malloc(sizeof(lash_map_simple_t));

    pymap = PyCapsule_New((void *)map, "MAP_C_API", mapDestroy);

    if (!PyArg_ParseTuple(args, "II", &w, &h))
        return NULL;

    lashMapSimpleInit(map, &w, &h);

    return Py_BuildValue("O", pymap);

} 

但是,当我实例化对象并将其删除或退出Python控制台时,析构函数似乎不会被调用:

>>> a = mapSimpleInit(10,20)
>>> a
<capsule object "MAP_C_API" at 0x7fcf4959f930>
>>> del(a)
>>> a = mapSimpleInit(10,20)
>>> a
<capsule object "MAP_C_API" at 0x7fcf495186f0>
>>> quit()
lash@CANTANDO ~/programming/src/liblashgame $ 

我的猜测是,它与Py_BuildValue()返回对&#34;胶囊&#34;的新引用有关,删除时不会影响原件。无论如何,我将如何确保对象被正确销毁?

使用Python 3.4.3 [GCC 4.8.4](在Linux上)

2 个答案:

答案 0 :(得分:1)

上面的代码有一个引用泄漏:pymap = PyCapsule_New()返回一个新对象(其引用计数为1),但Py_BuildValue("O", pymap)创建对同一对象的新引用,其引用现在为2。 / p>

只需return pymap;

答案 1 :(得分:0)

Py_BuildValue("O", thingy)只会增加thingy的引用计数并返回它 - 文档说它返回一个“新引用”但是当你传递一个现有的{{1}时,这不是真的}。

如果你的这些函数 - 你问题中的函数 - 都是在同一个翻译单元中定义的,那么析构函数可能必须被声明为PyObject*(因此它的完整签名将是{{ 1}})确保Python API可以在调用析构函数时正确查找函数的地址。

...只要内存中的析构函数地址有效,您就不必使用static函数。例如,我已成功使用a C++ non-capturing lambda as a destructor,因为非捕获C ++ lambdas可以转换为函数指针;如果你想使用另一种获取和交出胶囊析构函数的函数指针的方法,那么你可以选择更好的方法。