指针和 "Storing unsafe C derivative of temporary Python reference"

Pointers and "Storing unsafe C derivative of temporary Python reference"

我正在编写代码以将(可能)非常大的整数值存储到指针引用的 chars 数组中。我的代码如下所示:

cdef class Variable:

    cdef unsigned int Length
    cdef char * Array

    def __cinit__(self, var, length):
        self.Length = length
        self.Array = <char *>malloc(self.Length * sizeof(char))    # Error
        for i in range(self.Length):
            self.Array[i] = <char>(var >> (8 * i))

    def __dealloc__(self):
        self.Array = NULL

当我尝试编译代码时,在注释行出现错误 "Storing unsafe C derivative of temporary Python reference"。我的问题是:我在 C 中导出和存储哪个临时 Python 引用,我该如何修复它?

问题在于,在将数组赋值给 self.Array 之前,正在创建一个临时变量来保存数组,一旦方法退出,它就不再有效。

请注意 documentation 建议:

the C-API functions for allocating memory on the Python heap are generally preferred over the low-level C functions above as the memory they provide is actually accounted for in Python’s internal memory management system. They also have special optimisations for smaller memory blocks, which speeds up their allocation by avoiding costly operating system calls.

因此你可以像下面这样写,这似乎按预期处理了这个用例:

from cpython.mem cimport PyMem_Malloc, PyMem_Realloc, PyMem_Free

cdef class Variable:

    cdef unsigned int Length
    cdef char * Array

    def __cinit__(self, var,size_t length):
        self.Length = length
        self.Array = <char *>PyMem_Malloc(length * sizeof(char))
        #as in docs, a good practice
        if not self.Array:
            raise MemoryError()

        for i in range(self.Length):
            self.Array[i] = <char>(var >> (8 * i))

    def __dealloc__(self):
        PyMem_Free(self.Array)

@rll 的回答在清理代码和 "doing everything properly" 方面做得非常好(最重要的是问题中 __dealloc__ 缺少的内存重新分配!)。

导致错误的实际问题是您没有cimport编辑malloc。因此,Cython 假设 malloc 是一个 Python 函数,返回一个 Python 对象,您希望将其转换为 char*。在文件的顶部,添加

from libc.stdlib cimport malloc, free

它会起作用的。或者像@rll 那样使用 PyMem_Malloc(导入它),这也可以正常工作。