Jon*_*tan 1 wxwidgets boost-python
我正在使用Boost Python为wxWidgets子集创建绑定.wxWidgets中的窗口对象不应手动删除,因为它们处理自己的删除:例如,当用户单击关闭按钮关闭顶级窗口时,它会自动删除自身.如果一个窗口被删除,奇怪的事情将事件处理程序等情况的发生
(详情:http://docs.wxwidgets.org/2.8/wx_windowdeletionoverview.html)
但是这导致了在Python中创建的窗口对象的问题:在垃圾收集时,C++对象总是被删除!
有没有办法告诉Boost Python不要拥有它创建的C++对象?或许类似于构造函数的调用策略?
(另外,我有点担心如何处理从C++中删除的对象.当关联的C++对象被删除时,Python对象会发生什么?Python不会以任何方式得到通知.)
这可以通过boost::shared_ptrBoost.Python中的一些设置来完成.
boost::shared_ptr具有接受自定义删除器的构造函数.当shared_ptr引用计数达到零时,shared_ptr将调用客户删除器,将先前管理的指针作为参数传递.这允许使用不同的解除分配策略,例如"无操作"或调用的策略wxWindow::Destroy().
class window {};
void no_op(window*) {};
boost::shared_ptr(new window(), &no_op);
Run Code Online (Sandbox Code Playgroud)
将类暴露给Python时,Boost.Python允许通过类型管理类型HeldType.在这种情况下,HeldType将是boost::shared_ptr.这允许在C++和Python之间进行适当的引用计数,并允许自定义的释放策略.
boost::python::class_<window, boost::shared_ptr<window>, ...>("Window", ...);
Run Code Online (Sandbox Code Playgroud)
让这些透明地协同工作的诀窍是:
__init__)来抑制Boost.Python .__init__函数,该函数将调用返回shared_ptr带有自定义删除器的工厂函数.这是一个模拟window类,只能通过destroy()成员函数销毁.
class window
{
...
private:
~window();
public:
void destroy();
};
Run Code Online (Sandbox Code Playgroud)
定义了一个工厂函数,它将window使用自定义删除器创建引用计数对象.destroy()当引用计数达到零时,自定义删除器将在对象上调用.
boost::shared_ptr<window> create_window()
{
return boost::shared_ptr<window>(
new window(),
boost::mem_fn(&window::destroy));
}
Run Code Online (Sandbox Code Playgroud)
最后,使用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));
Run Code Online (Sandbox Code Playgroud)
这是一个完整的例子:
#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)
;
}
Run Code Online (Sandbox Code Playgroud)
它的用法:
>>> 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
Run Code Online (Sandbox Code Playgroud)
请注意,一旦Python不再引用该实例,Python只会通知C++删除该对象.因此,在这种情况下,Python不会尝试在已删除的对象上进行交互.希望这可以减轻在C++中删除对象时所表达的担忧.
如果有些情况下C++将删除仍在Python中处于活动状态的对象,那么请考虑使用不透明指针来分隔实现类和句柄类.句柄类可以在转发调用之前检查关联的实现实例是否已被删除,从而允许将异常抛出到Python.
| 归档时间: |
|
| 查看次数: |
1813 次 |
| 最近记录: |