考虑到到达对应的python对象的零引用计数的时刻,boost :: python是否可以保证包装对象的C ++析构函数被调用时提供任何保证?
我担心一个C ++对象,该对象会打开一个文件进行写入并在其析构函数中执行文件关闭操作。是否可以保证在删除对该对象的所有python引用或超出范围时都写入文件?
我是说:
A=MyBoostPythonObject()
del A # Is the C++ destructor of MyBoostPythonObject called here?
我的经验表明,析构函数总是在此时被调用,但是对此没有任何保证。
Boost.Python保证,如果Python对象拥有包装的C ++对象的所有权,那么当删除Python对象时,包装的C ++对象将被删除。Python对象的生存期由Python决定,其中,当对象的引用计数达到零时,该对象可能会立即被销毁。对于非简单情况,例如循环引用,这些对象将由垃圾回收器管理,并可能在程序退出之前被销毁。
一个Pythonic解决方案可能是公开一种实现上下文管理器协议的类型。内容管理器协议由一对方法组成:一种方法将在进入运行时上下文时被调用,而另一种方法将在退出运行时上下文时被调用。通过使用上下文管理器,可以控制打开文件的范围。
>>> with MyBoostPythonObject() as A: # opens file.
... A.write(...) # file remains open while in scope.
... # A destroyed once context's scope is exited.
这是一个示例,该示例演示将RAII类型的类作为上下文管理器暴露给Python:
#include <boost/python.hpp>
#include <iostream>
// Legacy API.
struct spam
{
spam(int x) { std::cout << "spam(): " << x << std::endl; }
~spam() { std::cout << "~spam()" << std::endl; }
void perform() { std::cout << "spam::perform()" << std::endl; }
};
/// @brief Python Context Manager for the Spam class.
class spam_context_manager
{
public:
spam_context_manager(int x): x_(x) {}
void perform() { return impl_->perform(); }
// context manager protocol
public:
// Use a static member function to get a handle to the self Python
// object.
static boost::python::object enter(boost::python::object self)
{
namespace python = boost::python;
spam_context_manager& myself =
python::extract<spam_context_manager&>(self);
// Construct the RAII object.
myself.impl_ = std::make_shared<spam>(myself.x_);
// Return this object, allowing caller to invoke other
// methods exposed on this class.
return self;
}
bool exit(boost::python::object type,
boost::python::object value,
boost::python::object traceback)
{
// Destroy the RAII object.
impl_.reset();
return false; // Do not suppress the exception.
}
private:
std::shared_ptr<spam> impl_;
int x_;
};
BOOST_PYTHON_MODULE(example)
{
namespace python = boost::python;
python::class_<spam_context_manager>("Spam", python::init<int>())
.def("perform", &spam_context_manager::perform)
.def("__enter__", &spam_context_manager::enter)
.def("__exit__", &spam_context_manager::exit)
;
}
互动用法:
>>> import example
>>> with example.Spam(42) as spam:
... spam.perform()
...
spam(): 42
spam::perform()
~spam()
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句