使用 Boost.Python 将 Python 对象的所有权转移到 C++ 代码

Pey*_*man 5 c++ python boost boost-python

我有一个抽象类Shape(来自 C++ 代码),并且我为它做了一个包装器,这样我就可以在 Python 中继承这个抽象类。除了一些内存管理问题之外,一切都运行良好。Python 对象被创建和销毁,而ShapeWrapperC++ 对象仍然存在。基本上,对象被销毁是因为Python中没有对它的引用,但在C++中存在对包装类的引用,所以我的想法是该类会wrapper增加初始化时的引用计数,并在C++时减少析构函数中的计数包装类ShapeWrap被破坏。但似乎这并没有发生在这里。这是一些代码:

Shape(C++ 中):

struct Shape {
    virtual inline string get_name() const = 0;
};
Run Code Online (Sandbox Code Playgroud)

班上ShapeWrap

struct ShapeWrap : public Shape, public wrapper<Shape> {
    string get_name() const override {
       if (auto py_func = this->get-override("get_name")) {
            return py_func();
       }
       return "Default String";
    }
}
Run Code Online (Sandbox Code Playgroud)

我这样定义类:

class_<ShapeWrap, shared_ptr<ShapeWrap>, boost::noncopyable>("Shape")
     .def("get_name", pure_virtual(&Shape::get_name));
Run Code Online (Sandbox Code Playgroud)

现在我这里有一个小函数来获取一个形状并打印出它的名称:

void print_name(shared_ptr<ShapeWrap> shape) {
    cout << shape->get_name() << endl;
}
Run Code Online (Sandbox Code Playgroud)

在 Python 领域我这样做:

class Circle(Shape):
    def __init__(self):
       super(Circle, self).__init__()
       print('Created')
    def __del__(self):
       print('Destroyed')
    def get_name(self):
       return "blah"

print_name(Circle())
Run Code Online (Sandbox Code Playgroud)

这就是我得到的

Created
blah
Destroyed
Run Code Online (Sandbox Code Playgroud)

但如果我这样做:

shared_ptr<ShapeWrap> create_shape(const object& cb) {
     return extract<shared_ptr<ShapeWrap>>(cb())();
}
Run Code Online (Sandbox Code Playgroud)

在 Python 中执行以下操作:

print_name(create_shape(lambda: Circle()))
Run Code Online (Sandbox Code Playgroud)

我明白了

Created
Destroyed
RuntimeError: Pure virtual function called
Run Code Online (Sandbox Code Playgroud)

ShapeWrap如果我在 的构造函数和析构函数中添加 cout我会得到这个

C++ Constructor
Created
Destroyed
RuntimeError: Pure virtual function called
C++ Destructor
Run Code Online (Sandbox Code Playgroud)

请注意,发生纯虚拟的事情是因为 Python 对象被销毁,因此没有覆盖方法,因此包装器会调用基本实现,这是引发 RuntiemError 异常的方法。