【问题标题】:passing C++ classes instances to python with boost::python使用 boost::python 将 C++ 类实例传递给 python
【发布时间】:2011-03-21 12:15:09
【问题描述】:

我有一个库,它创建对象(A 类的实例)并将它们传递给应该能够调用它们的方法的 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> >();
} 

代码缺少python获取existing_instance的部分。我没有粘贴,但假设我为此目的使用了回调机制。

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

  1. 在 Count 函数(以及所有其他 C++ 操作函数)中是否可以像这样传递 a 或者最好是像 const shared_ptr&lt;A&gt;&amp; 这样的传递?在我在 python boost 文档中找到的代码 sn-ps 中,经常使用引用,但我不明白其中的区别(当然,除了具有更高的引用计数器)。

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

  3. 我想阻止 python 创建 A 的实例。它们只能从 C++ 代码传递。我怎么能做到这一点? EDIT:找到了,我只需要使用 no_init 和 noncopyable:class_&lt;A, boost::noncopyable&gt;("A", no_init)

【问题讨论】:

    标签: c++ python boost boost-python


    【解决方案1】:

    boost::python 知道所有关于boost::shared_ptr,但您需要告诉它boost::shared_ptr&lt;A&gt; 拥有A 的实例,您可以通过将模板参数列表中的boost::shared_ptr&lt;A&gt; 添加到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
        ;
    

    一般中,您不应该通过引用传递共享指针,因为如果对共享指针的引用无效,那么共享指针指向的引用也会无效(因为采取共享指针的引用没有增加指向对象的引用计数器)。

    boost::shared_ptr 对象传入和传出python 是完全安全的,只要您不更改return_value_policy,引用计数(python 和shared_ptr)将得到正确管理。如果您更改在 python 中公开的方法的策略,使其返回对共享指针的引用,那么您可能会导致问题,就像通过 c++ 引用传递共享指针可能会导致问题一样。

    (另外,您应该使用make_shared&lt;A&gt;(...) 而不是shared_ptr&lt;A&gt;(new A(...))。)

    【解决方案2】:

    在这种情况下,我的代码将如下所示(以您的示例为例):

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

    禁止 boost::python 复制东西很重要,但如果你正在使用 shared_ptr 很有可能您只需要在少数受控情况下进行复制。

    【讨论】:

      猜你喜欢
      • 2011-06-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-25
      • 2014-02-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多