背景
之前有一个需求:在业务的某个阶段通过new方式创建了一个qmessagebox对象,点击该弹窗对象的按钮后删除该弹窗对象。
解决方法:采用信号槽的方式,点击弹窗上的按钮后,qmessagebox对象会发送buttonClicked(QAbstractButton*)信号,在该弹窗的信号的槽函数中,通过QObject提供的方法sender()可以获取发送信号的对象指针,然后对该指针调用deleteLater接口。起初采用的是在槽函数中直接调用delete删除对象,但是程序崩溃,分析原因应该是因为是同一个线程内的函数调用,相当于是同步调用,此时该对象业务逻辑还没有执行完成,删除该对象造成程序异常,导致程序崩溃。如果是异步调用应该没有问题,后面会专门写一篇文章分析qt信号槽的同步异步机制。
deleteLater接口总结
- deleteLater是QObject的成员函数,用于延迟删除QOjbect对象,对于以Qobject为基类的对象推荐使用deleteLater而非delete。
- deleteLater作用的对象必须是以QObject对象为基类的。并且类的声明中包含Q_OBJECT宏。因为其本质是在deleteLater的实现中发送了事件,要删除的对象接收该事件后再进行删除动作。事件名称为DeferrerDelete,原理如下:
void QObject::deleteLater()
{
QCoreApplication::postEvent(this, new QDeferredDeleteEvent());
}
...
bool QObject::event(QEvent *e)
{
switch (e->type()) {
....
case QEvent::DeferredDelete:
qDeleteInEventHandler(this);
break;
....
}
}
...
void qDeleteInEventHandler(QObject *o)
{
delete o;
}
- 调用QCoreApplication接口自己给自己发送 QDeferredDeleteEvent事件
- 在Qobject的event的实现中包含了对QDeferredDeleteEvent事件的处理
- 销毁对象
- 调用deleteLater后,至少在一个函数中依然可以访问该对象,因为原因是该对象还存在。