提升python make_constructor和托管人和病房

时间:2016-07-05 08:50:19

标签: python c++ boost-python

假设我有以下两个C ++类(我无法修改):

struct A
{
    // stuff
};

struct B
{
    // B will internally hold a reference to a
    B(A& a, some_cpp_only_type arg);
};

我正在尝试包装B类并从Python接口隐藏some_cpp_only_type参数(没有此参数的B没有替代构造函数。)

我现在有以下包装代码:

using namespace boost::python;

boost::shared_ptr<B> make_B(A& a)
{
    return boost::make_shared<B>(a, get_cpp_only_instance());
}

BOOST_PYTHON_MODULE(my_module)
{
    class_<B, boost::noncopyable>("B", no_init)
      .def("__init__", make_constructor(&make_B));
}

现在这是有效的,因为我在Python中持有对包装的A对象的引用。但是,我真的希望至少在B的实例被销毁之前保持这种状态。我尝试向with_custodian_and_ward_postcall添加make_constructor调用策略,但是我得到了几页无意义的编译错误(甚至来自Clang)。这是修改后的无效代码:

using namespace boost::python;

boost::shared_ptr<B> make_B(A& a)
{
    return boost::make_shared<B>(a, get_cpp_only_instance());
}

BOOST_PYTHON_MODULE(my_module)
{
    class_<B, boost::noncopyable>("B", no_init)
      .def("__init__", make_constructor(&make_B, with_custodian_and_ward_postcall<0,1>()));
}

使用make_constructor时如何正确指定通话政策?

使用make_function的替代尝试

我尝试使用make_function包裹的解决方案Tanner Sansbury posted here代替,但这次即使编译成功,我也会从Python内部获得ValueError

  

找不到C ++类型的to_python(by-value)转换器:A

作为参考,这里是我尝试过的使用make_function的代码(我在使用和不使用保管/病房调用策略时都会遇到相同的错误):

using namespace boost::python;

boost::shared_ptr<B> make_B(A& a)
{
    return boost::make_shared<B>(a, get_cpp_only_instance());
}

void inter_make_B(object self, A& a)
{
    auto constructor = make_constructor(&make_B);
    constructor(self, a);
}

BOOST_PYTHON_MODULE(my_module)
{
    class_<B, boost::noncopyable>("B", no_init)
      .def("__init__", make_function(&inter_make_B, with_custodian_and_ward<1,2>()));
}

如何在不修改B类的情况下正确编写正确管理内存的B包装器?

1 个答案:

答案 0 :(得分:1)

我知道这篇文章已有3年历史了,但是我本人正在寻找这篇文章,并且找不到对原始代码进行最小程度修改就可以立即使用的解决方案。感谢this other post,我终于设法使它能够正常工作。

以下是根据您提供的代码段进行的模拟:

using namespace boost::python;

boost::shared_ptr<B> make_B(A& a)
{
    return boost::make_shared<B>(a, get_cpp_only_instance());
}

void make_B_wrapper(object self, A& a)
{
    auto constructor = make_constructor(&make_B);
    constructor(self, a);
}

BOOST_PYTHON_MODULE(my_module)
{
    class_<B, boost::noncopyable>("B", no_init)
      .def("__init__", &make_B_wrapper, with_custodian_and_ward_postcall<1,2>());
}

这是example的完整工作,证明了这种方法:

#include <boost/python.hpp>
#include <boost/shared_ptr.hpp> 
#include <boost/make_shared.hpp> 
#include <iostream>

namespace python = boost::python;
  
/// @brief Mockup class with verbose construction and destruction.
class Foo
{
public:
  Foo() { std::cout << "Foo() " << this << std::endl; }
  ~Foo() { std::cout << "~Foo() " << this << std::endl; }
};

/// @brief Mockup class with verbose construction and destruction.
class Bar
{
public:
  Bar() { std::cout << "Bar() " << this << std::endl; }
  ~Bar() { std::cout << "~Bar() " << this << std::endl; }
};

/// @brief Mockup factory function.
boost::shared_ptr<Foo> makeFoo(std::shared_ptr<Bar> & /* unused */)
{
  return boost::make_shared<Foo>();
}

static void makeFooWrapper(python::object & self, std::shared_ptr<Bar> & bar)
{
    auto constructor = python::make_constructor(&makeFoo);
    constructor(self, bar);
}

BOOST_PYTHON_MODULE(example)
{
  python::class_<Bar, std::shared_ptr<Bar>, boost::noncopyable>("Bar", python::init<>());

  python::class_<Foo, std::shared_ptr<Foo>, boost::noncopyable>("Foo", python::no_init)
    .def("__init__", &makeFooWrapper,
                     python::with_custodian_and_ward_postcall<1, 2>());
}