无法从 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++ 引用时,此挂钩启用自定义策略来调用。