【问题标题】:Passing C++ objects to python with boost使用 boost 将 C++ 对象传递给 python
【发布时间】:2012-12-04 21:49:47
【问题描述】:

我正在尝试弄清楚如何使用 boost python 在 c++ 中创建一个对象并将其传递给 Python。我已经设法做到了,但无法进行垃圾收集。

想象类 A 是在 C++ 中的某个地方定义的。 passNewAToPython() 函数是从代码中的其他地方调用的,它创建一个 A 对象,然后将它传递给 Python 中的回调函数。我希望将特定实例传递给 python 而不是副本,因此使用 ptr()

static PyObject * pythonCallbacks;

void passNewAToPython()
{
  A * a = new A();
  PyGILState_STATE _GILState = PyGILState_Ensure();
  //Should really use a try catch here too but lets ignore that for now
  boost::python::call_method<void>(pythonCallbacks, "newA", boost::python::ptr(a));
  PyGILState_Release(_GILState);
}

void initmodule(PyObject* userCallCallbacks_)
{
   PyEval_InitThreads();

   pythonCallbacks = userCallCallbacks_;
}

BOOST_PYTHON_MODULE(mymodule)
{
    def("initmodule", initmodule);

    class_<A, boost::noncopyable>("A", init<>());
}

Python 代码

import mymodule

class pythonCallbacks(object):
    a_list = [];
    def newA(self, a):
         self.a_list.append(a)

callbacks = pythonCallbacks()
mymodule.initmodule(callbacks)

现在想象一下在调用 newA 回调之后的一段时间。我希望存储实例的唯一位置是在 a_list 中。因此,如果我从 a_list 中删除 a ,那么我希望在我使用 new 创建的对象上调用 c++ 删除。这永远不会发生,所以我泄漏了对象。

我已经尝试了许多技术变体来做到这一点,但从未设法使一切正常。我真的很感激一个完整的例子,也许可以展示如何修改上面的例子。

【问题讨论】:

  • 我对 boost::python 不熟悉,但是你在哪里释放 C++ 端的 python 对象引用计数?
  • C++端如何释放python对象引用计数?我已经看到了用于增加/减少引用计数的 BOOST 和 Python API 命令,但它们只对 python 对象进行操作。这里 python 对象是在 call_method 函数中创建的。在 call_method 完成后,我希望通过 Python 存在对该对象的唯一引用,以便当所有 Python 引用都消失时,该对象将被删除。我确实尝试过从指针中创建一个 boost::python::object ,然后调用它的增加/减少,但我通常只是崩溃。
  • 所以你专门转移了对象的所有权,在这种情况下你应该减少引用计数,除非目标方法不增加引用计数。
  • 你看过 PythonQt 吗?将 c++ 对象包装到 python 中非常简单!

标签: c++ python boost boost-python


【解决方案1】:

我很确定ptr() 与所指向对象的生命周期无关。如果您使用它,则完全由您来管理生命周期。 (我相信使用它就像使用 PyCObject。)

您可以做的是将 A 的指针类型定义为 shared_ptr(boost 或 std,无所谓)。像这样的:

class_<A, shared_ptr<A>, boost:noncopyable>("A", init<>());

然后你可以让你的工厂函数这样做:

void passNewAToPython()
{
    A * a = make_shared<A>();
    PyGILState_STATE _GILState = PyGILState_Ensure();     
    //Should really use a try catch here too but lets ignore that for now
    boost::python::call_method<void>(pythonCallbacks, "newA", a);
    PyGILState_Release(_GILState);
 }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-11-09
    • 2011-03-21
    • 2014-02-22
    • 2012-05-25
    • 1970-01-01
    • 2012-10-31
    • 2012-04-04
    相关资源
    最近更新 更多