Sturla Molden skrev:
> cdef class membuffer:
>
>     cdef readonly void *buf
>     cdef readonly Py_ssize_t nbytes
>
>     def __cinit__(membuffer self, Py_ssize_t nbytes):
>         self.buf = stdlib.malloc(nbytes)
>         if (self.buf == NULL):
>             raise MemoryError, 'malloc failed'
>         self.nbytes = nbytes
>
>     def __dealloc__(membuffer self):
>         if (self.buf): stdlib.free(self.buf)
>   

This design pattern is very important, because is avoids accidental 
memory leaks if an exception is raised. For the same reason, Python's C 
API has CObjects for storing C objects. They are used like this 
(ignoring error checking on malloc):

cdef extern from "Python.h":
    object PyCObject_FromVoidPointer(void *cobj, void (*destr*)(void*))
    void *PyCObject_AsVoidPointer(object self)

cdef object buf =  
PyCObject_FromVoidPointer(stdlib.malloc(nbytes),stdlib.free)
cdef void *pbuf = PyCObject_AsVoidPointer(buf)

The advantage is, similar to the membuffer class above, that a matching 
call to free is gurarranteed. If you just put calls to malloc/free 
randomly into Cython, a portion of the code could be skipped when an 
exception is raised, and a memory leak would result. Manual memory 
management is more tricky than it appears on the surface.

In plain C, there are no exceptions, but you can still get the problem 
if someone uses setjmp/longjmp. If you know there is no longjmps, you 
can use malloc/free rather safely.

In C++ there are exceptions, and std::vector is therefore much safter 
than operators new[] and delete[]. It is generally newer safe to use 
new[] and delete[] outside constructors and destructors, and doing so is 
the number one cause of memory leaks in C++. Unfortunately, C++ textbook 
teach bad habits, including using operator new[] anywhere.

Cython is just like C++: you can get exceptions thrown! Therefore, put 
all manual allocations in __cinit__ and all manual deallocations in 
__dealloc__. That will prevent bad resource leaks in case of an 
exception being raised. Just putting calls to malloc/free randomly into 
Cython code is syntactially legal, but not a design pattern I would 
recommend.

Sorry for ranting...

S.M.
_______________________________________________
Cython-dev mailing list
[email protected]
http://codespeak.net/mailman/listinfo/cython-dev

Reply via email to