gpt4 book ai didi

wxwidgets - 使 Boost Python 不删除析构函数中的 C++ 对象

转载 作者:行者123 更新时间:2023-12-05 01:21:38 25 4
gpt4 key购买 nike

我正在使用 Boost Python 为 wxWidgets 的子集创建绑定(bind)。 wxWidgets 中的窗口对象不应该手动删除,因为它们处理自己的删除:例如,当用户单击关闭按钮关闭顶层窗口时,它会自动删除自己。如果一个窗口删除,事件处理程序等将会发生奇怪的事情。

(详情:http://docs.wxwidgets.org/2.8/wx_windowdeletionoverview.html)

然而,这会导致在 Python 中创建的窗口对象出现问题:在垃圾回收时,C++ 对象总是被删除!

有没有办法告诉 Boost Python 不要取得它创建的 C++ 对象的所有权?也许是构造函数的调用策略?

(此外,我有点担心如何处理从 C++ 中删除的对象。当关联的 C++ 对象被删除时,Python 对象会发生什么?Python 不会以任何方式收到有关此的通知。)

最佳答案

这可以通过 boost::shared_ptr 来完成以及 Boost.Python 中的一些设置。

boost::shared_ptr 具有接受自定义删除器的构造函数。当 shared_ptr 的引用计数达到零时,shared_ptr 将调用客户删除器,将先前管理的指针作为参数传递。这允许使用不同的释放策略,例如“无操作”,或调用 wxWindow::Destroy() 的策略。

class window {};
void no_op(window*) {};
boost::shared_ptr(new window(), &no_op);

当向 Python 公开一个类时,Boost.Python 允许通过 HeldType 管理类型。在这种情况下,HeldType 将为 boost::shared_ptr。这允许在 C++ 和 Python 之间进行正确的引用计数,并允许自定义释放策略。

boost::python::class_<window, boost::shared_ptr<window>, ...>("Window", ...);

让它们透明地协同工作的技巧是:

  • 禁止 Boost.Python 创建默认初始化程序 (__init__)。
  • 明确提供一个 __init__ 函数,该函数将调用一个工厂函数,返回一个带有自定义删除器的 shared_ptr

这是一个模拟的 window 类,旨在仅通过 destroy() 成员函数销毁。

class window
{
...
private:
~window();
public:
void destroy();
};

定义了一个工厂函数,它将创建一个带有自定义删除器的引用计数 window 对象。当引用计数达到零时,自定义删除器将在对象上调用 destroy()

boost::shared_ptr<window> create_window()
{
return boost::shared_ptr<window>(
new window(),
boost::mem_fn(&window::destroy));
}

最后,使用 Boost.Python 公开 window 类,但抑制默认初始化程序,并透明地将其替换为 create_window 工厂函数。

boost::python::class_<window, boost::shared_ptr<window>, 
boost::noncopyable>("Window", python::no_init)
.def("__init__", python::make_constructor(&create_window));

这是一个完整的例子:

#include <iostream>
#include <boost/mem_fn.hpp>
#include <boost/python.hpp>
#include <boost/shared_ptr.hpp>

/// @brief Mockup window class.
class window
{
public:
window(unsigned int id)
: id_(id)
{
std::cout << "window::window() " << id_ << std::endl;
}
void action() { std::cout << "window::action() " << id_ << std::endl; }
void destroy()
{
std::cout << "window::destroy() " << id_ << std::endl;
delete this;
}
private:
~window() { std::cout << "window::~window() " << id_ << std::endl; }
private:
unsigned int id_;
};

/// @brief Factory function that will create reference counted window
/// objects, that will call window::destroy() when the reference
/// count reaches zero.
boost::shared_ptr<window> create_window(unsigned int id)
{
return boost::shared_ptr<window>(
new window(id),
boost::mem_fn(&window::destroy));
}

BOOST_PYTHON_MODULE(example) {
namespace python = boost::python;
// Expose window, that will be managed by shared_ptr, and transparently
// constructs the window via a factory function to allow for a custom
// deleter.
python::class_<window, boost::shared_ptr<window>,
boost::noncopyable>("Window", python::no_init)
.def("__init__", python::make_constructor(&create_window))
.def("action", &window::action)
;
}

及其用法:

>>> from example import Window
>>> w1 = Window(1)
window::window() 1
>>> w2 = Window(2)
window::window() 2
>>> w3 = Window(3)
window::window() 3
>>> del w2
window::destroy() 2
window::~window() 2
>>> w3 = None
window::destroy() 3
window::~window() 3
>>> w = w1
>>> del w1
>>> w.action()
window::action() 1
>>> w = None
window::destroy() 1
window::~window() 1

请注意,一旦 Python 不再具有对实例的引用,Python 如何仅通知 C++ 删除该对象。因此,在这种情况下,Python 不会尝试与已删除的对象进行交互。希望这可以减轻在 C++ 中删除对象时表达的担忧。

如果在某些情况下,C++ 会删除在 Python 中仍处于事件状态的对象,那么请考虑使用 opaque pointer将实现类和句柄类分开。句柄类可以在转发调用之前检查关联的实现实例是否已被删除,从而允许向 Python 抛出异常。

关于wxwidgets - 使 Boost Python 不删除析构函数中的 C++ 对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14642216/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com