Cython: overloaded constructor initialization using raw pointer
I'm trying to wrap two C++ classes: Cluster and ClusterTree. ClusterTree has a method get_current_cluster() that instantiates a Cluster object, and returns a reference to it. ClusterTree owns the Cluster object, and manages its creation and deletion in C++.
I've wrapped Cluster with cython, resulting in PyCluster.
PyCluster should have two ways of creation:
1) By passing in two arrays, which then implies that Python should then automatically handle deletion (via __dealloc__)
2) By directly passing in a raw C++ pointer (created by ClusterTree's get_current_cluster()). In this case, ClusterTree then assumes responsibility of deleting the underlying pointer.
from libcpp cimport bool from libcpp.vector cimport vector cdef extern from "../include/Cluster.h" namespace "Terran": cdef cppclass Cluster: Cluster(vector[vector[double]],vector[int]) except + cdef class PyCluster: cdef Cluster* __thisptr __autoDelete = True def __cinit__(self, vector[vector[double]] data, vector[int] period): self.__thisptr = new Cluster(data, period) @classmethod def __constructFromRawPointer(self, raw_ptr): self.__thisptr = raw_ptr self.__autoDelete = False def __dealloc__(self): if self.__autoDelete: del self.__thisptr cdef extern from "../include/ClusterTree.h" namespace "Terran": cdef cppclass ClusterTree: ClusterTree(vector[vector[double]],vector[int]) except + Cluster& getCurrentCluster() cdef class PyClusterTree: cdef ClusterTree *__thisptr def __cinit__(self, vector[vector[double]] data, vector[int] period): self.__thisptr = new ClusterTree(data,period) def __dealloc__(self): del self.__thisptr def get_current_cluster(self): cdef Cluster* ptr = &(self.__thisptr.getCurrentCluster()) return PyCluster.__constructFromRawPointer(ptr)
This results in:
Error compiling Cython file: ------------------------------------------------------------ ... def get_current_cluster(self): cdef Cluster* ptr = &(self.__thisptr.getCurrentCluster()) return PyCluster.__constructFromRawPointer(ptr) ^ ------------------------------------------------------------ terran.pyx:111:54: Cannot convert 'Cluster *' to Python object
Note I cannot cdef __init__ or @classmethods.
Pointers can only be passed to cdef'd functions as arguments, and cinit has to be def'd. But providing a classmethod is almost the way to go!
cdef Cluster* __thisptr
cdef bool __wrapped ## defaults to False
@staticmethod
cdef PyCluster wrap(Cluster* ptr):
cdef PyCluster pc = PyCluster([], []) ## Initialize as cheaply as possible
del pc.__thisptr ## delete the old pointer to avoid memory leaks!
pc.__thisptr = ptr
pc.__wrapped = True
return pc
I know this is an old question, but after my own recent struggles with Cython I thought I'd post an answer for the sake of posterity.
It seems to me you could use a copy constructor to create a new PyCluster object from an existing Cluster object.
Define the copy constructor in your C code, then call the copy constructor in the Python class definition (in this case, when a pointer is passed) using new
. This will work, although it may not be the best or most performant solution.