python之boost python make_constructor 和 custodians 和 ward

落叶无声 阅读:34 2025-04-02 23:11:03 评论:0

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

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

我正在尝试包装 B 类并隐藏 some_cpp_only_type来自 Python 接口(interface)的参数(没有此参数的 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)); 
} 

现在这有效,因为我持有对已包装 A 的引用Python内部的对象。但是,我真的很想至少在 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 的替代尝试

我尝试使用解决方案 Tanner Sansbury posted heremake_function 包装相反,但这一次即使编译成功,我也会得到 ValueError从 Python 内部:

No to_python (by-value) converter found for C++ type: 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 即可正确管理内存类(class)?

请您参考如下方法:

我知道这篇文章已经有 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>()); 
} 


标签:Python
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

关注我们

一个IT知识分享的公众号