简而言之,Boost.Python不支持移动语义,因此不支持
std::unique_ptr。Boost.Python的新闻/更改日志不表示已针对C
++
11移动语义进行了更新。此外,此功能要求为
unique_ptr支持还未触碰了一年多。
尽管如此,Boost.Python支持通过来往于Python和从Python转移对象的专有所有权
std::auto_ptr。从
unique_ptr本质上来说
auto_ptr,它是更安全的版本,因此将API改编成使用
unique_ptr以下的API应该是相当简单的
auto_ptr:
- 当C 将所有权转让给Python时,C 函数必须:
- 被暴露与CallPolicy
boost::python::return_value_policy
用boost::python::manage_new_object
结果转换器。 unique_ptr
通过具有释放控制release()
并返回原始指针
- 被暴露与CallPolicy
- 当Python将所有权转让给C 时,C 函数必须:
- 通过接受实例
auto_ptr
。在常见问题中提到,从C ++与返回的指针manage_new_object
政策将通过进行管理std::auto_ptr
。 - 对通孔具有
auto_ptr
释放控制unique_ptr``release()
- 通过接受实例
给定一个无法更改的API /库:
/// @brief Mockup Spam class.struct Spam;/// @brief Mockup factory for Spam.struct SpamFactory{ /// @brief Create Spam instances. std::unique_ptr<Spam> make(const std::string&); /// @brief Delete Spam instances. void consume(std::unique_ptr<Spam>);};
的
SpamFactory::make()和
SpamFactory::consume()需要经由辅助功能缠绕。
将所有权从C ++转移到Python的函数通常可以由创建Python函数对象的函数包装:
/// @brief Adapter a member function that returns a unique_ptr to/// a python function object that returns a raw pointer but/// explicitly passes ownership to Python.template <typename T, typename C, typename ...Args>boost::python::object adapt_unique(std::unique_ptr<T> (C::*fn)(Args...)){ return boost::python::make_function( [fn](C& self, Args... args) { return (self.*fn)(args...).release(); }, boost::python::return_value_policy<boost::python::manage_new_object>(), boost::mpl::vector<T*, C&, Args...>() );}
lambda委托给原始函数,并将
releases()实例的所有权委托给Python,并且调用策略表明Python将获取从lambda返回的值的所有权。,
mpl::vector描述了Boost.Python的调用签名,从而使其能够正确管理语言之间的函数分配。
的结果显示
adapt_unique为
SpamFactory.make():
boost::python::class_<SpamFactory>(...) .def("make", adapt_unique(&SpamFactory::make)) // ... ;
一般而言,适应
SpamFactory::consume()比较困难,但是编写一个简单的辅助函数很容易:
/// @brief Wrapper function for SpamFactory::consume_spam(). This/// is required because Boost.Python will pass a handle to the/// Spam instance as an auto_ptr that needs to be converted to/// convert to a unique_ptr.void SpamFactory_consume( SpamFactory& self, std::auto_ptr<Spam> ptr) // Note auto_ptr provided by Boost.Python.{ return self.consume(std::unique_ptr<Spam>{ptr.release()});}
辅助函数将委托给原始函数,并将
auto_ptrBoost.Python提供的函数转换
unique_ptr为API所需的函数。的
SpamFactory_consume辅助函数被公开为
SpamFactory.consume():
boost::python::class_<SpamFactory>(...) // ... .def("consume", &SpamFactory_consume) ;
这是完整的代码示例:
#include <iostream>#include <memory>#include <boost/python.hpp>/// @brief Mockup Spam class.struct Spam{ Spam(std::size_t x) : x(x) { std::cout << "Spam()" << std::endl; } ~Spam() { std::cout << "~Spam()" << std::endl; } Spam(const Spam&) = delete; Spam& operator=(const Spam&) = delete; std::size_t x;};/// @brief Mockup factor for Spam.struct SpamFactory{ /// @brief Create Spam instances. std::unique_ptr<Spam> make(const std::string& str) { return std::unique_ptr<Spam>{new Spam{str.size()}}; } /// @brief Delete Spam instances. void consume(std::unique_ptr<Spam>) {}};/// @brief Adapter a non-member function that returns a unique_ptr to/// a python function object that returns a raw pointer but/// explicitly passes ownership to Python.template <typename T, typename ...Args>boost::python::object adapt_unique(std::unique_ptr<T> (*fn)(Args...)){ return boost::python::make_function( [fn](Args... args) { return fn(args...).release(); }, boost::python::return_value_policy<boost::python::manage_new_object>(), boost::mpl::vector<T*, Args...>() );}/// @brief Adapter a member function that returns a unique_ptr to/// a python function object that returns a raw pointer but/// explicitly passes ownership to Python.template <typename T, typename C, typename ...Args>boost::python::object adapt_unique(std::unique_ptr<T> (C::*fn)(Args...)){ return boost::python::make_function( [fn](C& self, Args... args) { return (self.*fn)(args...).release(); }, boost::python::return_value_policy<boost::python::manage_new_object>(), boost::mpl::vector<T*, C&, Args...>() );}/// @brief Wrapper function for SpamFactory::consume(). This/// is required because Boost.Python will pass a handle to the/// Spam instance as an auto_ptr that needs to be converted to/// convert to a unique_ptr.void SpamFactory_consume( SpamFactory& self, std::auto_ptr<Spam> ptr) // Note auto_ptr provided by Boost.Python.{ return self.consume(std::unique_ptr<Spam>{ptr.release()});}BOOST_PYTHON_MODULE(example){ namespace python = boost::python; python::class_<Spam, boost::noncopyable>( "Spam", python::init<std::size_t>()) .def_readwrite("x", &Spam::x) ; python::class_<SpamFactory>("SpamFactory", python::init<>()) .def("make", adapt_unique(&SpamFactory::make)) .def("consume", &SpamFactory_consume) ;}
交互式Python:
>>> import example>>> factory = example.SpamFactory()>>> spam = factory.make("a" * 21)Spam()>>> spam.x21>>> spam.x *= 2>>> spam.x42>>> factory.consume(spam)~Spam()>>> spam.x = 100Traceback (most recent call last): File "<stdin>", line 1, in <module>Boost.Python.ArgumentError: Python argument types in None.None(Spam, int)did not match C++ signature: None(Spam {lvalue}, unsigned int)
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)