我有一个库创建对象(类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
的部分。我没有粘贴它,但是我只是说我为此目的使用了一个回调机制。
此代码有效,但我有几个问题:
在Count函数(以及所有其他C ++操作函数中)可以这样传递a
或者更好地执行const shared_ptr<A>&
之类的操作吗?在我在python boost文档中找到的代码片段中经常使用引用,但我不理解其中的区别(当然除了有更高的引用计数器)。
此代码“安全”吗?当我将existing_instance传递给python时,它的计数器将递增(只有一次,即使在python中我制作了更多的对象副本,当然)所以C ++代码没有办法可以破坏对象,就像python一样至少是一个“副本”。我对么?我试着用指针玩,看来我是对的,我只想确定一下。
我想阻止python创建A的实例。它们只能从C ++代码传递。我怎么能实现这一目标? 编辑:发现,我只需要使用no_init和noncopyable:class_<A, boost::noncopyable>("A", no_init)
答案 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很可能只需要在一些受控情况下进行复制。