Suppose that you have a C++ class (I'll call it Foo) which you want to wrap for access from python. There would be two basic ways to go about managing this structure:
__new__
function in my
python/Cython object and delete in the __dealloc__
. This method
is pretty easy to understand from a C++ perspective.
We let the details of the first option as an exercise to the reader and provide a more elaborate description for the second option. Use code like the following to embed the object in the Cython extension class structure:
cdef class FooWrapper: cdef Foo x
This may appear to work fine because many C++ constructors don't do a whole lot of interesting work and Cython zeroes out the memory in these structures. However, there is a problem since neither the constructor nor destructor are called for Foo since the memory is allocated with malloc (or PyMalloc or something). So, you need to call the constructor and destructor manually. The rest of this section provides a simple way to do so.
The main trick is that we need to call the constructor of Foo, but the memory
is already allocated. An important nuance of the C++ new
operator is
described here:
http://publib.boulder.ibm.com/infocenter/macxhelp/v6v81/index.jsp?topic=/com.ibm.vacpp6m.doc/language/ref/clrc05cplr199.htm.
There is a C++ header file in the sage_c_lib
which defines some templated
functions to make writing wrappers for C++ classes more convenient. You can
make the following declarations in a pxd or pxi file for use from Cython.
cdef extern from "Foo.h": ctypedef struct Foo: pass cdef extern from "ccobject.h": # Some non-allocating versions Foo* Foo_construct "Construct<Foo>"(void *mem) void Foo_destruct "Destruct<Foo>"(Foo *mem) # some allocating versions for completeness Foo* Foo_new "New<Foo>"() void Foo_delete "Delete<Foo>"(Foo *mem)
Now, we need to call these functions we defined from our Cython
__new__
and __dealloc__
functions.
cdef class FooWrapper: def __init__(self, ...): pass # Note that the parameters to __new__ must be identical to __init__ # This is due to some Cython vagary def __new__(self, ...): Foo_construct(&self.x) def __dealloc__(self): Foo_destruct(&self.x)
See About this document... for information on suggesting changes.