我已经构建了一个带有两个字段的简单Structure子类,它包含一个指向数组的void指针和数组长度。但是,当我尝试使用相同长度的输入列表创建这些列表时,返回的void指针的值与用于创建实例的最后一个数组相同:
from ctypes import POINTER, c_double, c_size_t, c_void_p, Structure, cast
import numpy as np
class External(Structure):
_fields_ = [("data", c_void_p),
("length", c_size_t)]
@classmethod
def from_param(cls, seq):
return seq if isinstance(seq, cls) else cls(seq)
def __init__(self, seq):
self.ptr = cast(
np.array(seq, dtype=np.float64).ctypes.data_as(POINTER(c_double)),
c_void_p
)
self.data = self.ptr
self.length = len(seq)
# recreate array from void pointer
# shows the correct values
shape = self.length, 2
ptr = cast(self.data, POINTER(c_double))
array = np.ctypeslib.as_array(ptr, shape)
print "Correct array", array.tolist()
if __name__ == "__main__":
interiors = [
[[3.5, 3.5], [4.4, 2.0], [2.6, 2.0], [3.5, 3.5]],
[[4.0, 3.0], [4.0, 3.2], [4.5, 3.2], [4.0, 3.0]],
]
wrong = [External(s) for s in interiors]
for w in wrong:
# perform same cast back to array as before
shape = w.length, 2
ptr = cast(w.data, POINTER(c_double))
array = np.ctypeslib.as_array(ptr, shape)
print "Wrong array", array.tolist()
如果我使用不同长度的输入列表创建我的External
实例,那么一切都按预期工作。我在这里做错了什么?
答案 0 :(得分:2)
问题是numpy数组立即被垃圾收集,底层内存被释放,导致悬空指针。
解决方案是保留对基础buffer
对象的引用:
def __init__(self, seq):
array = np.array(seq, dtype=np.float64)
self._buffer = array.data
self.ptr = cast(
array.ctypes.data_as(POINTER(c_double)),
c_void_p
)
...
现在只有当持有引用的External
实例被删除时才会释放数组的内存。