且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

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

更新时间:2022-02-12 23:59:47

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

Boost.Python makes the guarantee that if the Python object has ownership of the wrapped C++ object, then when the Python object is deleted, the wrapped C++ object will be deleted. The Python object's lifetime is dictated by Python, wherein when an object’s reference count reaches zero, the object may be immediately destroyed. For non-simplistic cases, such as cyclic references, the objects will be managed by the garbage collector, and may be destroyed before the program exits.

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

One Pythonic solution may be to expose a type that implements the context manager protocol. The content manager protocol is made up of a pair of methods: one which will be invoked when entering a runtime context, and one which will be invoked when exiting a runtime context. By using a context manager, one could control the scope in which a file is open.

>>> with MyBoostPythonObject() as A:  # opens file.
...     A.write(...)                  # file remains open while in scope.
...                                   # A destroyed once context's scope is exited.


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


Here is an example demonstrating exposing a RAII-type class to Python as a context manager:

#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()