如何在Cython中 Package 来自C++的std::shared_ptr和std::vector?

lf5gs5x2  于 2023-03-05  发布在  其他
关注(0)|答案(2)|浏览(192)

我正在尝试用Cython将一个C++库封装到一个python API中。我想封装的类有以下模板:

template<typename Value>
class ClassToWrap
{

public:
    typedef std::shared_ptr<std::vector<Value> > TypeToWrap;

    ClassToWrap(TypeToWrap data)
    {
    }
}

我对C++标准库不太有信心。我如何在Cython中 Package TypeToWrap,使其可以像数组或多维数组一样以简单的方式初始化,例如使用赋值循环?谢谢您的建议。

sqougxex

sqougxex1#

假设您有一个C++头文件,如下所示:

// cpp_class.h

#include <memory>
#include <vector>

template<typename Value>
class ClassToWrap
{
public:
    typedef std::shared_ptr<std::vector<Value> > TypeToWrap;

    ClassToWrap(TypeToWrap data) : obj(data)  // you could do a move here
    {
    }
private:
    TypeToWrap obj;
};

你需要将这个类公开给cython,这是通过cython wrapping Cpp文档中的cdef extern完成的。

# my_cy_class.pyx

# distutils: language = c++

from libcpp.memory cimport make_shared, shared_ptr
from libcpp.vector cimport vector

cdef extern from "cpp_class.h" nogil:
    cdef cppclass ClassToWrap[T]:
        ctypedef shared_ptr[vector[T]] TypeToWrap
        ClassToWrap(TypeToWrap)
        # define anything you intend to use

注意你只需要定义函数,而不是它们的实现。
其次,我们定义一个cython类来 Package 它并将其暴露给python,因为python要使用它,所以它需要知道T的类型,我们假设它是一个int

from cython.operator cimport dereference as deref
from libcpp.utility cimport move

cdef class wrapper_class:
    cdef ClassToWrap[int]* wrapped_obj  # needs to be a defined type and heap allocated

    def __cinit__(self, some_list):
        cdef vector[int] v = some_list
        cdef ClassToWrap[int].TypeToWrap ptr = make_shared[vector[int]](move(v))
        self.wrapped_obj = new ClassToWrap[int](move(ptr))
        # deref(self.wrapped_obj).foo()

    def __dealloc__(self):
        del self.wrapped_obj

你可能想知道为什么要使用一个指向对象的指针?原因是你的对象没有默认的零参数构造函数,而cython需要一个默认的零参数构造函数来堆栈分配它,使用一个__cinit__和一个__dealloc__保证没有内存泄漏
注意,some_list不一定是python列表,它可以很容易地是numpy数组,事先知道类型可以帮助编译器优化它的代码,下面的代码可以测试它。

import pyximport
script_args = ["--cython-cplus"]
setup_args = {
    "script_args": script_args,
    "include_dirs": ['.'],

}
pyximport.install(setup_args=setup_args, language_level=3,)

import numpy as np
import my_cy_class

inputs = np.array([1,2,3,4,5])
a = my_cy_class.wrapper_class(inputs)
ct3nt3jp

ct3nt3jp2#

如果一个对象被删除了,你应该给予Python一个指针,并创建一个双向观察模式(通知双方)!并且你可以重置shared_ptr。例如:

class CythonWrapClass {
 public:
  CythonWrapClass(std::shared_ptr<Foo> sharedFoo) : foo(sharedFoo) {
    // cython communication in the class anywhere
    // assume cython object variable in the class has name: cthon
    // cthon should take the pointer of Foo and work with it but when it has
    // finished it should notify to this pointer (exactly this instance)
    // when destroying notified from python it will decrease refcount
  }

  // cthon will call this function when it finished its job with sharedFoo
  void onDestroyFromcthon() { foo.reset(); }

 private:
  std::shared_ptr<Foo> foo;
};

相关问题