无法从python C ++包装器访问析构函数 [英] Can not access destructor from python C++ wrapper

查看:265
本文介绍了无法从python C ++包装器访问析构函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图将一些现有的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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆