Python ctypes,C++对象销毁

5
考虑以下Python ctypes - C++绑定代码:
// C++
class A
{
public:
    void someFunc();
};

A* A_new() { return new A(); }
void A_someFunc(A* obj) { obj->someFunc(); }
void A_destruct(A* obj) { delete obj; }

# python
from ctypes import cdll

libA = cdll.LoadLibrary(some_path)

class A:
    def __init__(self):
        self.obj = libA.A_new()

    def some_func(self):
        libA.A_someFunc(self.obj)

当不再需要python对象时,删除c++对象的最佳方法是什么。

[编辑] 我添加了建议的delete函数,但问题仍然存在于何时以及由谁调用该函数。应尽可能方便。

3个回答

10

你可以实现__del__方法,调用一个你需要定义的析构函数:

C++

class A
{
public:
    void someFunc();
};

A* A_new() { return new A(); }
void delete_A(A* obj) { delete obj; }
void A_someFunc(A* obj) { obj->someFunc(); }

Python

from ctypes import cdll

libA = cdll.LoadLibrary(some_path)

class A:
    def __init__(self):
        fun = libA.A_new
        fun.argtypes = []
        fun.restype = ctypes.c_void_p
        self.obj = fun()

    def __del__(self):
        fun = libA.delete_A
        fun.argtypes = [ctypes.c_void_p]
        fun.restype = None
        fun(self.obj)

    def some_func(self):
        fun = libA.A_someFunc
        fun.argtypes = [ctypes.c_void_p]
        fun.restype = None
        fun(self.obj)

还要注意您在__init__方法上遗漏了self参数。此外,您需要明确指定返回类型/参数类型,因为ctypes默认为32位整数,而在现代系统上指针可能为64位。

有些人认为__del__是有害的。作为替代方案,您可以使用with语法:

class A:
    def __init__(self):
        fun = libA.A_new
        fun.argtypes = []
        fun.restype = ctypes.c_void_p
        self.obj = fun()

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        fun = libA.delete_A
        fun.argtypes = [ctypes.c_void_p]
        fun.restype = None
        fun(self.obj)

    def some_func(self):
        fun = libA.A_someFunc
        fun.argtypes = [ctypes.c_void_p]
        fun.restype = None
        fun(self.obj)

with A() as a:
    # Do some work
    a.some_func()

del 函数什么时候被调用? - tauran
A的引用计数归零时,在对象被清理之前。 - Marcelo Cantos
有没有关于这个的任何保证?在Python文档中找不到它们。这是否意味着Python决定何时执行__del__方法? - tauran
1
@tauran:请参考以下链接了解有关引用计数的信息:这个这个 - Björn Pollex

2

通常,dll应该提供一种方法来清理它们创建的对象。这样,内存分配就封装在dll中。这意味着,您的dll应该可能会公开一个类似于void A_delete(A*)的方法。


2
从DLL中导出一个函数以释放对象。这样做是为了确保在分配对象时负责内存管理的机制也被用于释放对象。请注意保留HTML标签。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接