Conventions for memory management and destructors / free() with Python's CFFI?

673 views Asked by At

If I'm wrapping a C class:

from ._ffi import ffi, lib

class MyClass(object):
     def __init__(self):
         self._c_class = lib.MyClass_create()

What are best practices for making sure that lib.MyClass_destroy(…) is called?

Does cffi have some sort of wrapper around objects that will call a destructor when the Python object is GC'd, for example something like:

my_obj = managed(lib.MyClass_create(), destructor=lib.MyClass_destroy)

Or should that destructor logic be in the class's __del__? Something like:

class MyClass(object):
    def __del__(self):
        if self._c_class is not None:
            lib.MyClass_destroy(self._c_class)

What are the best practices here?

1

There are 1 answers

0
David Wolever On

It looks like ffi.gc() is the way to go. This is the small wrapper I've written which also does the post-malloc NULL check:

def managed(create, args, free):
    o = create(*args)
    if o == ffi.NULL:
        raise MemoryError("%s could not allocate memory" %(create.__name__, ))
    return ffi.gc(o, free)

For example:

c_class = managed(lib.MyClass_create, ("some_arg", 42),
                  lib.MyClass_destroy)