在Cython中包装自定义类型C ++指针

时间:2015-02-27 17:32:45

标签: python c++ pointers numpy cython

使用Cython包装自定义类型C ++指针的最佳方法是什么?

例如:

import numpy as np
cimport numpy as np

cdef extern from "A_c.h"
    cdef cppclass A:
       A();
       void Foo(A* vec);

cdef class pyA:
    cdef A *thisptr
    def ___cinit___(self):
        self.thisptr = new A()
    def __dealloc___(self):
        del self.thisptr

我应该如何使用cython来包装Foo?我已经尝试了以下但是我从Buffer.py得到了断言错误或者A不是memoryview slice的基本类型的错误

def Foo(self, np.ndarray[A, mode='c'] vec)
def Foo(self, A[::1] vec)   

1 个答案:

答案 0 :(得分:2)

基本上每次要传递类型为A的对象或指向它的指针时,都应该使用类型为pyA的Python对象 - 这实际上非常类似于指向事实的指针它有引用计数,所以它就像C ++ 11中的shared_ptr,只是它只知道Python(或Cython)中的引用。 [编辑]请注意,Python对象可以是None,您可以使用not None子句轻松阻止它。

当然,这不仅适用于参数,也适用于返回类型,因此返回指向A类型的对象的指针的每个方法都应返回pyA - 对象。为此,您可以为示例cdef创建一个setThis方法名称,以允许设置包含的指针。

如上所述,如果以这种方式包装指针,内存管理是在Python中完成的,所以一方面你需要确保如果你的C ++对象拥有一个指向一个对象的指针,那么Python对象就不会被删除(例如,在Cython中存储对Python对象的引用)另一方面,如果它们仍然包含在Python对象中,则不应该从C ++中删除对象。如果在C ++中已经有某种内存管理,那么如果要删除C ++对象,你也可以为你的Cython对象添加标志。

为了说明如何在Cython中实现这一点,我稍微扩展了您的示例:

cdef extern from "A_c.h":
    cdef cppclass A:
        A()
        void Foo(A* vec)
        A* Bar()

    cdef cppclass AContainer:
        AContainer(A* element)

cdef class pyA:
    cdef A *thisptr
    def ___cinit___(self):
        self.thisptr = new A()

    def __dealloc___(self):
        del self.thisptr

    cdef setThis(self, A* other):
        del self.thisptr
        self.thisptr = other
        return self

    def Foo(self, pyA vec not None): # Prevent passing None
        self.thisptr.Foo(vec.thisptr)

    def Bar(self):
        return pyA().setThis(self.thisptr.Bar())

cdef class pyAContainer:
    cdef AContainer *thisptr
    cdef pyA element

    def __cinit__(self, pyA element not None):
        self.element = element # store reference in order to prevent deletion
        self.thisptr = new AContainer(element.thisptr)

    def __dealloc__(self):
        del self.thisptr # this should not delete the element
        # reference counting for the element is done automatically