14

我有一个库,它创建对象(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<A>&?在我在 python boost 文档中找到的代码片段中,经常使用参考,但我不明白其中的区别(当然,除了具有更高的参考计数器)。

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

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

4

2 回答 2

14

boost::python什么都知道boost::shared_ptr,但你需要告诉它boost::shared_ptr<A>持有一个实例A,你可以通过boost::shared_ptr<A>在模板参数列表中添加来做到这一点class_,关于这个“持有类型”的更多信息在boost 文档中。

为了防止从 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 中公开的方法的策略,使其返回对共享指针的引用,那么您可能会导致问题,就像通过 c++ 引用传递共享指针可能会导致问题一样。

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

于 2010-07-31T13:00:49.323 回答
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 ,您可能只需要在少数受控情况下进行复制。

于 2010-07-27T13:21:48.153 回答