如何在Cython中封装C++的std::shared_ptr和std::vector?

huangapple go评论76阅读模式
英文:

How to wrap std::shared_ptr and std::vector from C++ in Cython?

问题

我正在尝试使用Cython将一个C++库封装为Python API。我想要封装的类具有以下模板:

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

    ClassToWrap(TypeToWrap data)
    {
    }
}

我对C++标准库不太自信。我该如何在Cython中封装TypeToWrap,以便可以像数组或多维数组一样以简单的方式进行初始化,例如通过分配的for循环?感谢任何建议。

英文:

I am trying to wrap a C++ library into a python API with Cython. The class I want to wrap has the following template:

template&lt;typename Value&gt;
class ClassToWrap
{

public:
    typedef std::shared_ptr&lt;std::vector&lt;Value&gt; &gt; TypeToWrap;

    ClassToWrap(TypeToWrap data)
    {
    }
}

I'm not confident with C++ standard library. How I can wrap the TypeToWrap in Cython in a way that it can be inizialized in a simple way like an array or a multidimenstional array, for example with a for loop of assignments? Thanks for any suggestion.

答案1

得分: 2

以下是您要翻译的代码部分:

// 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(std::move(data))
    {
    }
private:
    TypeToWrap obj;
}
# 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
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
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)
英文:

let's assume you have a C++ header as follows:

// cpp_class.h

#include &lt;memory&gt;
#include &lt;vector&gt;

template&lt;typename Value&gt;
class ClassToWrap
{
public:
    typedef std::shared_ptr&lt;std::vector&lt;Value&gt; &gt; TypeToWrap;

    ClassToWrap(TypeToWrap data) : obj(std::move(data))
    {
    }
private:
    TypeToWrap obj;
};

you would need to expose this class to cython, this is done by a cdef extern from cython wrapping Cpp documentation.

# my_cy_class.pyx

# distutils: language = c++

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

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

note that you only need to define the functions, not their implementations.

secondly, let's define a cython class to wrap it and expose it to python, since python is going to use it, it needs to know the type of T, let's assume it is an 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

you may be wondering why a pointer to an object is used ? the reason is because your object has no default zero arguments constructor, and cython requires a default zero arguments constructor to be able to stack allocate it, using a __cinit__ and a __dealloc__ guarantee no memory leaks

note that some_list doesn't need to be a python list, it can easily be a numpy array, and knowing the type beforehand can help the compiler optimize the code for it, the following code can test it.

import pyximport
script_args = [&quot;--cython-cplus&quot;]
setup_args = {
    &quot;script_args&quot;: script_args,
    &quot;include_dirs&quot;: [&#39;.&#39;],

}
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)

答案2

得分: 1

你应该将指针传递给Python并创建一个双向观察模式(通知双方),以便在对象被删除时进行通知!并且你可以重置 shared_ptr。例如:

class CythonWrapClass {
 public:
  CythonWrapClass(std::shared_ptr<Foo> sharedFoo) : foo(sharedFoo) {
    // 在类的任何地方进行Cython通信
    // 假设类中的Cython对象变量名为: cthon
    // cthon 应该获取 Foo 的指针并与其一起工作,但在完成后应该通知到这个指针(确切地是这个实例)
    // 在从Python销毁时得到通知,它将减少引用计数
  }

  // 当cthon完成与sharedFoo的工作时,cthon将调用这个函数
  void onDestroyFromcthon() { foo.reset(); }

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

You should give the pointer to Python and create a bidirectional observing pattern (notify both sides) if an object is deleted! and you can reset the shared_ptr. i.e:

class CythonWrapClass {
 public:
  CythonWrapClass(std::shared_ptr&lt;Foo&gt; 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&lt;Foo&gt; foo;
};

huangapple
  • 本文由 发表于 2023年3月3日 19:11:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/75626349.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定