boost::python 包装对象的 C++ 析构函数调用

ovg*_*vga 2 c++ python boost-python

考虑到相应 python 对象的引用计数达到零的时刻,当调用包装对象的 C++ 析构函数时,boost::python 是否提供任何保证?

我担心一个 C++ 对象打开一个文件进行写入并在其析构函数中执行文件关闭。当对对象的所有 python 引用都被删除或超出范围时,是否保证写入文件?

我是说:

A=MyBoostPythonObject()
del A # Is the C++ destructor of MyBoostPythonObject called here?
Run Code Online (Sandbox Code Playgroud)

我的经验表明,析构函数总是在此时被调用,但对此找不到任何保证。

Tan*_*ury 5

Boost.Python 保证,如果 Python 对象拥有包装的 C++ 对象的所有权,那么当删除 Python 对象时,包装的 C++ 对象也将被删除。Python 对象的生命周期由 Python 规定,其中当对象 xe2x80x99s 引用计数达到零时,该对象可能会立即被销毁。对于非简单的情况,例如循环引用,对象将由垃圾收集器管理,并且可能在程序退出之前被销毁。

\n\n

一种 Pythonic 解决方案可能是公开一种实现上下文管理器协议的类型。内容管理器协议由一对方法组成:一个在进入运行时上下文时将被调用,另一个将在退出运行时上下文时被调用。通过使用上下文管理器,人们可以控制文件打开的范围。

\n\n
>>> with MyBoostPythonObject() as A:  # opens file.\n...     A.write(...)                  # file remains open while in scope.\n...                                   # A destroyed once context\'s scope is exited.\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

下面是一个示例,演示了将 RAII 类型的类作为上下文管理器公开给 Python:

\n\n
#include <boost/python.hpp>\n#include <iostream>\n\n// Legacy API.\nstruct spam\n{\n  spam(int x)    { std::cout << "spam(): " << x << std::endl;   }\n  ~spam()        { std::cout << "~spam()" << std::endl;         }\n  void perform() { std::cout << "spam::perform()" << std::endl; }\n};\n\n/// @brief Python Context Manager for the Spam class.\nclass spam_context_manager\n{\npublic:\n\n  spam_context_manager(int x): x_(x) {}\n\n  void perform() { return impl_->perform(); }\n\n// context manager protocol\npublic:\n\n  // Use a static member function to get a handle to the self Python\n  // object.\n  static boost::python::object enter(boost::python::object self)\n  {\n    namespace python = boost::python;\n    spam_context_manager& myself =\n      python::extract<spam_context_manager&>(self);\n\n    // Construct the RAII object.\n    myself.impl_ = std::make_shared<spam>(myself.x_);\n\n    // Return this object, allowing caller to invoke other\n    // methods exposed on this class.\n    return self;\n  }\n\n  bool exit(boost::python::object type,\n            boost::python::object value,\n            boost::python::object traceback)\n  {\n    // Destroy the RAII object.\n    impl_.reset();\n    return false; // Do not suppress the exception.\n  }\nprivate:\n  std::shared_ptr<spam> impl_;\n  int x_;\n};\n\n\nBOOST_PYTHON_MODULE(example)\n{\n  namespace python = boost::python;\n  python::class_<spam_context_manager>("Spam", python::init<int>())\n    .def("perform", &spam_context_manager::perform)\n    .def("__enter__", &spam_context_manager::enter)\n    .def("__exit__", &spam_context_manager::exit)\n    ;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

互动使用:

\n\n
>>> import example\n>>> with example.Spam(42) as spam:\n...     spam.perform()\n...\nspam(): 42\nspam::perform()\n~spam()\n
Run Code Online (Sandbox Code Playgroud)\n