无法从 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。
实现此目的的一种方法是使用接受 A*
并委托给 func(const A&)
.
的辅助函数
boost::python::def("func", +[](A* a) { return func(*a); });
当函数直接通过 boost::python::def()
公开时,Boost.Python 将尝试为在语言障碍之间传递的参数注册转换器。为了减少悬挂引用的可能性,Python 将对任何非指针参数进行按值转换。通过使用辅助,在函数调度期间将使用指针的 from-Python 转换器。
这是一个完整的示例demonstrating,它使用辅助函数来避免按值转换。它还展示了如何使用 boost::shared_ptr
显式自定义销毁通过 Boost.Python:
公开的 class
#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; });
}
交互使用:
>>> 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())
请注意,在上面的示例中,spam
实例由 boost::shared_ptr
管理,自定义删除器不会删除实例。当对象不再被 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。
实现此目的的一种方法是使用接受 A*
并委托给 func(const A&)
.
boost::python::def("func", +[](A* a) { return func(*a); });
当函数直接通过 boost::python::def()
公开时,Boost.Python 将尝试为在语言障碍之间传递的参数注册转换器。为了减少悬挂引用的可能性,Python 将对任何非指针参数进行按值转换。通过使用辅助,在函数调度期间将使用指针的 from-Python 转换器。
这是一个完整的示例demonstrating,它使用辅助函数来避免按值转换。它还展示了如何使用 boost::shared_ptr
显式自定义销毁通过 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; });
}
交互使用:
>>> 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())
请注意,在上面的示例中,spam
实例由 boost::shared_ptr
管理,自定义删除器不会删除实例。当对象不再被 Python 或 C++ 引用时,此挂钩启用自定义策略来调用。