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.

链接地址: http://www.djcxy.com/p/87926.html

上一篇: 内存泄漏调用具有大型numpy数组参数的cython函数?

下一篇: Cython:使用原始指针重载构造函数初始化