2010-07-27 103 views
13

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

基本上我有C++类实例,我想从Python使用它们。偶尔该对象应该传回给C++进行一些操作。

我创建了下面的封装文件(让我们假设New功能某处在C++代码中调用):

#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> >(); 
} 

代码缺少其中蟒蛇得到existing_instance的一部分。我没有粘贴,但我们只是说我为此使用了回调机制。

此代码的工作,但我有几个问题:

  1. 在计数功能(和所有其他C++操作函数)是精细传递a一样,或者最好是像做const shared_ptr<A>& ?在我在python boost文档中找到的代码片段中,经常使用该引用,但我不了解其中的差别(当然,除了具有较高的引用计数器外)。

  2. 此代码是否“安全”?当我将existing_instance传递给python时,它的计数器会增加(只是一次,即使在python中,我也会创建更多的对象副本),所以没有办法让C++代码可以销毁对象,只要python成立至少一个“复制”。我对么?我试图玩弄指针,似乎我是正确的,我只是想确定一下。

  3. 我想阻止python创建实例A.他们应该只能从C++代码传递。我怎么能做到这一点? 编辑:发现,我只需要使用NO_INIT和不可复制:class_<A, boost::noncopyable>("A", no_init)

回答

14

boost::python知道所有关于boost::shared_ptr,但你需要告诉它boost::shared_ptr<A>持有A一个实例,您可以通过在模板参数列表中添加boost::shared_ptr<A>class_做到这一点,在这个“举行类型”的更多信息是here in the boost documentation

为了防止情况下被蟒蛇创建,添加boost::python::no_init到class_的构造函数,所以你最终:

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

一般你不应该通过引用传递围绕共享指针,因为如果对共享指针的引用无效,则共享指针指向的引用也被无效(因为引用共享指针时不会将引用计数器递增到指向的对象)。

将对象周围的boost::shared_ptr对象传入或传出python是完全安全的,只要您不更改return_value_policy,引用计数(python和shared_ptr)将被正确管理。如果你改变了暴露在python中的方法的策略,以便它返回对共享指针的引用,那么你可能会导致问题,就像通过C++引用传递共享指针可能会导致问题一样。

(。此外,你应该使用make_shared<A>(...)优先于shared_ptr<A>(new A(...))

+0

什么之间的区别(实际上) “class_ (” A “NO_INIT)” 和“提升: :python :: class_ >(“A”,boost :: python :: no_init)“? 即使没有在“class_”之后指定“boost :: shared_ptr ”,我发布的代码仍然完美。那么,为什么我需要这个? – Emiliano 2010-08-01 16:27:33

+0

它指定了实际上由python“A”包装的默认类型 - 所以如果你有一个C++函数返回一个'A','A *'shared_ptr或者类似的东西,并且暴露给python,那么返回值将被保存为shared_ptr - 如果您经常将这些对象传入或传出python,那么它将会被正确处理。 有关更多信息,请参见http://www.boost.org/doc/libs/1_43_0/libs/python/doc/v2/class.html#HeldType(尤其是第2点)。 – James 2010-08-01 17:32:46

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的机会是你只需要在几个受控的情况下复制。

相关问题