Python ctypes与C++对象销毁

5 投票
3 回答
4800 浏览
提问于 2025-04-16 04:13

考虑一下下面这个 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++ 对象的最佳方法是什么?

[编辑] 我添加了建议的删除函数,但问题依然存在:这个函数应该由谁来调用,以及什么时候调用。它应该尽可能方便。

3 个回答

2

从DLL中导出一个函数,用来释放对象。这样做是为了确保在释放对象时,使用的内存管理方式和分配对象时是一样的。

2

一般来说,dll(动态链接库)应该提供一种方法来清理它们创建的对象。这样一来,内存的分配就被封装在dll内部。这意味着,你的dll可能需要提供一个像 void A_delete(A*) 这样的清理方法。

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()

撰写回答