使用boost :: python将C ++类实例传递给python

时间:2010-07-27 09:21:48

标签: c++ python boost boost-python

我有一个库创建对象(类A的实例)并将它们传递给python程序,该程序应该能够调用它们的方法。

基本上我有C ++类实例,我想从python中使用它们。有时,该对象应该传递回C ++进行一些操作。

我创建了以下包装器文件(假设在C ++代码中的某处调用了New函数):

#include <boost/python.hpp>
#include <iostream>
#include <boost/smart_ptr.hpp>

using namespace boost;
using namespace boost::python;

int calls = 0;

struct A
{
   int f() { return calls++; }
   ~A() { std::cout << "destroyed\n"; }
};

shared_ptr<A> existing_instance;

void New() { existing_instance = shared_ptr<A>( new A() ); }

int Count( shared_ptr<A> a ) { return a.use_count(); }

BOOST_PYTHON_MODULE(libp)
{
    class_<A>("A")
        .def("f", &A::f)
    ;

    def("Count", &Count);

    register_ptr_to_python< shared_ptr<A> >();
} 

代码缺少python获取existing_instance的部分。我没有粘贴它,但是我只是说我为此目的使用了一个回调机制。

此代码有效,但我有几个问题:

  1. 在Count函数(以及所有其他C ++操作函数中)可以这样传递a或者更好地执行const shared_ptr<A>&之类的操作吗?在我在python boost文档中找到的代码片段中经常使用引用,但我不理解其中的区别(当然除了有更高的引用计数器)。

  2. 此代码“安全”吗?当我将existing_instance传递给python时,它的计数器将递增(只有一次,即使在python中我制作了更多的对象副本,当然)所以C ++代码没有办法可以破坏对象,就像python一样至少是一个“副本”。我对么?我试着用指针玩,看来我是对的,我只想确定一下。

  3. 我想阻止python创建A的实例。它们只能从C ++代码传递。我怎么能实现这一目标? 编辑:发现,我只需要使用no_init和noncopyable:class_<A, boost::noncopyable>("A", no_init)

2 个答案:

答案 0 :(得分:14)

boost::python了解boost::shared_ptr的全部内容,但您需要告诉boost::shared_ptr<A>拥有A的实例,您可以通过添加boost::shared_ptr<A>来实现此目的模板参数列表为class_,有关此“保留类型”的更多信息为here in the boost documentation

为了防止从python创建实例,你将boost::python::no_init添加到class_构造函数中,所以最终得到:

boost::python::class_< A, boost::shared_ptr<A> >("A", boost::python::no_init)
    //... .def, etc
    ;

general 中,你不应该通过引用传递共享指针,因为如果对共享指针的引用无效,那么共享指针指向的引用也会失效(因为共享指针的引用没有将引用计数器增加到指向的对象)。

boost::shared_ptr对象传递给python是非常安全的,如果不更改return_value_policy,将正确管理引用计数(python和shared_ptr)。如果你更改python中公开的方法的策略,以便它返回对共享指针的引用,那么你可能会导致问题,就像通过c ++引用传递共享指针一样可能会导致问题。

(另外,您应优先使用make_shared<A>(...) shared_ptr<A>(new A(...))。)

答案 1 :(得分:1)

在这种情况下,我的代码看起来像这样(对于你的例子):

...

BOOST_PYTHON_MODULE(libp)
{
    class_<A, boost::shared_ptr<A>, boost::noncopyable >("A")
       .def("f", &A::f)
       .def("Count", &Count)
     ;
 } 

重要的是禁止boost :: python复制内容,但如果你正在使用它 shared_ptr很可能只需要在一些受控情况下进行复制。