我正在使用 ctypes 从 python 访问 c 库(它实际上是 c++ 代码):
class CRMeAnnotationList(object):
def __init__(self):
self.obj = lib.CRMeAnnotationList_new()de
def __del__(self):
if self.obj:
lib.CRMeAnnotationList_destroy(self.obj)
lst = CRMeAnnotationList()
C 代码如下所示
extern "C" {__declspec(dllexport) CRMeAnnotationList* CRMeAnnotationList_new()
{ return new CRMeAnnotationList();
}
__declspec(dllexport)void CRMeAnnotationList_destroy(CRMeAnnotationList* p)
{
if (p)
delete p;
}
}
这段代码给了我 完成,退出代码 -1073741819 (0xC0000005)
而如果我不销毁指针,我会得到 0 作为退出代码。
这是否意味着我不需要销毁该指针,即执行 python 代码中的析构函数部分 del ?
最佳答案
您可能正在运行 64 位 Python,并且尚未正确设置 .argtypes
和 .restype
。
示例:
测试.cpp
#define API __declspec(dllexport) // Windows-specific
extern "C" {
struct CRMeAnnotationList {
int a;
};
API CRMeAnnotationList* CRMeAnnotationList_new() {
return new CRMeAnnotationList();
}
API void CRMeAnnotationList_destroy(CRMeAnnotationList* p) {
if(p)
delete p;
}
}
测试.py
from ctypes import *
lib = CDLL('test')
lib.CRMeAnnotationList_new.argtypes = None
lib.CRMeAnnotationList_new.restype = c_void_p
lib.CRMeAnnotationList_destroy.argtypes = c_void_p,
lib.CRMeAnnotationList_destroy.restype = None
class CRMeAnnotationList:
def __init__(self):
print(f'created {id(self):#x}')
self.obj = lib.CRMeAnnotationList_new()
def __del__(self):
print(f'destroyed {id(self):#x}')
if self.obj:
lib.CRMeAnnotationList_destroy(self.obj)
lst = CRMeAnnotationList()
输出:
created 0x2232dfc35c0
destroyed 0x2232dfc35c0
当 .argtypes
和 .restype
行被注释掉时的输出:
created 0x1c98e8f35c0
destroyed 0x1c98e8f35c0
Exception ignored in: <function CRMeAnnotationList.__del__ at 0x000001C98E9176A8>
Traceback (most recent call last):
File "C:\Users\metolone\Desktop\test.py", line 16, in __del__
OSError: exception: access violation reading 0xFFFFFFFF8C6CABCF
记下访问冲突的地址。它是一个 32 位值,符号扩展为 64 位。
关于python ctypes 垃圾回收,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54066070/