无法从python C ++包装器访问析构函数 [英] Can not access destructor from python C++ wrapper
问题描述
我试图将一些现有的C ++函数包装到python中。我将我的问题简化为下面的代码:
#include< boost / python.hpp>
class A {〜A(); };
void func(const A&);
int main(int argc,char ** argv){
boost :: python :: def(func,func);
}
我得到访问私有析构函数A ::〜A的错误。注意,A ::〜A在我的情况下必须是不可访问的,我不能修改现有的C ++代码。注意2,上面的例子将编译func获取指针而不是引用。
void func(const A *);
我想解释boost :: python,它不能删除对象A在我的情况。 / p>
一个方法是使用辅助函数接受 A *
,并委托 func(const A&)
。
boost :: python :: def(func,+ [](A * a){return func(* a);});
当一个函数直接通过 boost :: python :: def()
,Boost.Python将尝试为在语言障碍之间传递的参数注册转换器。为了减少悬挂引用的机会,Python将对任何非指针参数执行一个值转换。通过使用辅助函数,在函数分派期间将使用一个来自Python转换器的指针。
使用辅助功能演示,以避免按值转换。它还显示了如何使用 boost :: shared_ptr
来显式定制通过Boost.Python暴露的类的销毁:
< pre class =lang-cpp prettyprint-override>
#include< boost / python.hpp>
#include< boost / shared_ptr.hpp>
命名空间{
int func_count = 0;
} //命名空间
//旧模型。
class spam
{
private:
〜spam(){};
};
//传统API。
void func(const spam&)
{
++ func_count;
};
/// @brief工厂函数用
创建垃圾邮件实例///自定义删除器。
boost :: shared_ptr< spam> make_spam()
{
//使用无操作删除器创建一个新的垃圾邮件实例。
auto no_op = + [](void *){};
return boost :: shared_ptr< spam>(new spam(),no_op);
}
BOOST_PYTHON_MODULE(example)
{
namespace python = boost :: python;
//使用自定义删除程序公开类A。
python :: class_< spam,boost :: shared_ptr< spam>,
boost :: noncopyable>(Spam,python :: no_init)
.def(__ init__,python :: make_constructor(& make_spam))
;
//使用辅助函数来避免在语言边界的
//的值转换。这防止Boost.Python
//创建实例持有者,它将值
//作为右值。
python :: def(func,+ [](spam * spam){return func(* spam);});
python :: def(get_count,+ [](){return func_count;});
}
互动用法:
< pre class =lang-python prettyprint-override>
>>> import example
>>> spam = example.Spam()
>>>> assert(0 == example.get_count())
>>> example.func(spam)
>>>> assert(1 == example.get_count())
>>>尝试:
... example.func(1)
... assert(False)
...除了TypeError:
... pass
.. 。
>>>> assert(1 == example.get_count())
请注意,在上面的示例中, spam
实例由具有不删除实例的自定义删除程序的 boost :: shared_ptr
管理。当一个对象不再被Python或C ++引用时,此钩子使自定义策略能够调用。
I'm trying to wrap some existing C++ functions to python. I simplified my problem to the code listed below:
#include <boost/python.hpp>
class A { ~A( ); };
void func( const A& );
int main( int argc, char** argv ){
boost::python::def( "func", func );
}
I get error about accessing private destructor A::~A. Note, A::~A must be inaccessible in my case and I can not modify existing C++ code. Note2, sample above will compile if func get pointer instead of reference.
void func( const A* );
I would like to explain boost::python that it must not delete object A in my case.
One way to accomplish this is to use an auxiliary function that accepts a A*
, and delegates to func(const A&)
.
boost::python::def("func", +[](A* a) { return func(*a); });
When a function is exposed directly through boost::python::def()
, Boost.Python will attempt to register converters for arguments that pass between the language barrier. To mitigate the chance of dangling references, Python will do a by-value conversion for any non-pointer arguments. By using the auxiliary, a from-Python converter by pointer will be used during function dispatch.
Here is a complete example demonstrating using an auxiliary function to avoid a by-value conversion. It also shows how to use boost::shared_ptr
to explicitly customize the destruction of a class exposed through Boost.Python:
#include <boost/python.hpp>
#include <boost/shared_ptr.hpp>
namespace {
int func_count = 0;
} // namespace
// Legacy model.
class spam
{
private:
~spam() {};
};
// Legacy API.
void func(const spam&)
{
++func_count;
};
/// @brief Factory function to create Spam instances with
/// a custom deleter.
boost::shared_ptr<spam> make_spam()
{
// Create a new spam instance with a no-op deleter.
auto no_op = +[](void*) {};
return boost::shared_ptr<spam>(new spam(), no_op);
}
BOOST_PYTHON_MODULE(example)
{
namespace python = boost::python;
// Expose class A with a custom deleter.
python::class_<spam, boost::shared_ptr<spam>,
boost::noncopyable>("Spam", python::no_init)
.def("__init__", python::make_constructor(&make_spam))
;
// Use an auxiliary function to avoid by-value conversion
// at the language boundary. This prevents Boost.Python
// from creating instance holders that would hold the value
// as an rvalue.
python::def("func", +[](spam* spam){ return func(*spam); });
python::def("get_count", +[]() { return func_count; });
}
Interactive usage:
>>> import example
>>> spam = example.Spam()
>>> assert(0 == example.get_count())
>>> example.func(spam)
>>> assert(1 == example.get_count())
>>> try:
... example.func(1)
... assert(False)
... except TypeError:
... pass
...
>>> assert(1 == example.get_count())
Note that in the above example, the spam
instances are managed by a boost::shared_ptr
with a custom deleter that does not delete the instance. This hook enables custom strategies to invoke when an object is no longer referenced by Python or C++.
这篇关于无法从python C ++包装器访问析构函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!