5.4.3 Embedding C++ objects in Cython extension structures

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:

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.