来自 C++ 的回调 python 函数,对象被破坏

Posted

技术标签:

【中文标题】来自 C++ 的回调 python 函数,对象被破坏【英文标题】:callback python function from C++ , object destructed 【发布时间】:2019-09-12 14:41:02 【问题描述】:

我执行一段python代码生成C++对象并回调一个python函数,然后把这个对象返回给python,为什么对象被破坏了?

我使用boost python来包装我的C++程序并从python创建一个对话框。然后当点击一个按钮时,回调一个python函数,将这个对象指针返回到这个函数,但是对象成员数据似乎全部清除了

class MyObj

public:
   OtherThing();
   ConnectFunc(boost::python::object callbackfun)m_pyCallbackFunc=callbackfun;
   //some operation will call below function 
   DoSomething()m_pyCallbackFunc(this)
private:
   boost::python::object m_pyCallbackfunc;
   vector<int> m_vecData;


def callback(myobject):
   #call my object functions again 
   myobject.Otherthing()

//first generate C++ object by python ,such as 
obj=MyObj
obj.ConnectFunc(callback)....

一切顺利,但执行OtherThing()函数时,成员数据 m_vecData 已被清除。我发现当调用python函数“回调”时, MyObj会调用销毁函数,所以数据已经被清除了

任何人都可以帮助我如何避免它,我想保留它吗?或者有人给我个好主意

【问题讨论】:

【参考方案1】:

当您执行以下操作时:

DoSomething()m_pyCallbackFunc(this)

您的m_pyCallbackFunc 从这个副本接收一个新的代理对象,这意味着它接收到的对象不是接收到的DoSomething 对象。假设你有以下类:

class Foo

public:
    boost::python::object bar()
    
        return boost::python::object(boost::python::ptr(this));
    
;

您导出的内容如下:

boost::python::class_<Foo>("Foo")
    .def(
        "bar",
        &Foo::bar
    );

假设foo.bar() 会返回foo 是安全的,但事实并非如此。以下将引发断言错误:

foo = Foo()
assert foo is foo.bar()

因为返回的是一个新的代理对象。如果你想将同一个对象传回 Python,你必须声明你的类,比如 Boost know it has back references,或者我最喜欢的;将您的方法声明为静态并提取您的实例:

class Foo

public:
    static boost::python::object bar(boost::python::object self)
    
        Foo &pSelf = boost::python::extract<Foo &>(self);
        return self;
    
;

现在上面的代码将不再引发断言错误,因为返回的对象与接收到的对象相同。基本上,您的析构函数被调用是因为代理对象创建的副本超出范围并被释放。

【讨论】:

以上是关于来自 C++ 的回调 python 函数,对象被破坏的主要内容,如果未能解决你的问题,请参考以下文章

通过 Boost Python 将 Python 函数转换为 C++,用作回调

Pybind11:为啥来自 Python 的异步调用不能在 C++ 中正确执行回调?

来自不同类的C++多个回调成员函数,没有std和boost

C++ template —— 函数对象和回调(十四)

使用 SWIG 包装对象从 C++ 调用 Python 函数的最简洁方法是啥

使用 C++ 类成员函数作为 C 回调函数