Qt deleteLater 延迟删除原理
deleteLater 调用
事件发送
void QObject::deleteLater()
{QCoreApplication::postEvent(this, new QDeferredDeleteEvent());
}
- 首先该对象继承QObject
- 调用deleteLater, 内部会发送删除事件
QCoreApplication::postEvent(this, new QDeferredDeleteEvent())
到事件循环的队列中 - 最终事件循环会调用 reciver->event(Qevent)
事件接收
bool QObject::event(QEvent *e)
{switch (e->type()) {case QEvent::Timer:timerEvent((QTimerEvent*)e);break;case QEvent::ChildAdded:case QEvent::ChildPolished:case QEvent::ChildRemoved:childEvent((QChildEvent*)e);break;case QEvent::DeferredDelete:qDeleteInEventHandler(this);break;...return true;
}void qDeleteInEventHandler(QObject *o)
{delete o;
}
- event(QEvent *e) 通过事件类型判断,是否为
延迟删除类型:QEvent::DeferredDelete
- 如果是延迟删除类型,则会调用
qDeleteInEventHandler
事件发送实现
设置删除事件的 looplevel 和 eventLevel
void QCoreApplication::postEvent(QObject *receiver, QEvent *event, int priority)
{Q_TRACE_SCOPE(QCoreApplication_postEvent, receiver, event, event->type());if (receiver == nullptr) {qWarning("QCoreApplication::postEvent: Unexpected null receiver");delete event;return;}auto locker = QCoreApplicationPrivate::lockThreadPostEventList(receiver);if (!locker.threadData) {// posting during destruction? just delete the event to prevent a leakdelete event;return;}QThreadData *data = locker.threadData;// if this is one of the compressible events, do compressionif (receiver->d_func()->postedEvents&& self && self->compressEvent(event, receiver, &data->postEventList)) {Q_TRACE(QCoreApplication_postEvent_event_compressed, receiver, event);return;}if (event->type() == QEvent::DeferredDelete)receiver->d_ptr->deleteLaterCalled = true;if (event->type() == QEvent::DeferredDelete && data == QThreadData::current()) {// remember the current running eventloop for DeferredDelete// events posted in the receiver's thread.// Events sent by non-Qt event handlers (such as glib) may not// have the scopeLevel set correctly. The scope level makes sure that// code like this:// foo->deleteLater();// qApp->processEvents(); // without passing QEvent::DeferredDelete// will not cause "foo" to be deleted before returning to the event loop.// If the scope level is 0 while loopLevel != 0, we are called from a// non-conformant code path, and our best guess is that the scope level// should be 1. (Loop level 0 is special: it means that no event loops// are running.)int loopLevel = data->loopLevel;int scopeLevel = data->scopeLevel;if (scopeLevel == 0 && loopLevel != 0)scopeLevel = 1;static_cast<QDeferredDeleteEvent *>(event)->level = loopLevel + scopeLevel;}// delete the event on exceptions to protect against memory leaks till the event is// properly owned in the postEventListQScopedPointer<QEvent> eventDeleter(event);Q_TRACE(QCoreApplication_postEvent_event_posted, receiver, event, event->type());data->postEventList.addEvent(QPostEvent(receiver, event, priority));eventDeleter.take();event->posted = true;++receiver->d_func()->postedEvents;data->canWait = false;locker.unlock();QAbstractEventDispatcher* dispatcher = data->eventDispatcher.loadAcquire();if (dispatcher)dispatcher->wakeUp();
}
通过looplevel 和 eventLevel 判断 确认是是否执行延迟删除事件
const bool allowDeferredDelete =(eventLevel > loopLevel|| (!eventLevel && loopLevel > 0)|| (event_type == QEvent::DeferredDelete&& eventLevel == loopLevel));if (!allowDeferredDelete) {// cannot send deferred deleteif (!event_type && !receiver) {// we must copy it first; we want to re-post the event// with the event pointer intact, but we can't delay// nulling the event ptr until after re-posting, as// addEvent may invalidate pe.QPostEvent pe_copy = pe;// null out the event so if sendPostedEvents recurses, it// will ignore this one, as it's been re-posted.const_cast<QPostEvent &>(pe).event = nullptr;// re-post the copied event so it isn't lostdata->postEventList.addEvent(pe_copy);}continue;}
- 如果符合条件 调用
QCoreApplication::sendEvent(r, e);
- 不符合条件 制空当前队列指针
const_cast<QPostEvent &>(pe).event = nullptr;
,将指针副本插入到队列尾部 continue 跳过``(完成一次延迟删除的机会)
最总调用event 事件:
bool QCoreApplicationPrivate::notify_helper(QObject *receiver, QEvent * event)
{// Note: when adjusting the tracepoints in here// consider adjusting QApplicationPrivate::notify_helper too.Q_TRACE(QCoreApplication_notify_entry, receiver, event, event->type());bool consumed = false;bool filtered = false;Q_TRACE_EXIT(QCoreApplication_notify_exit, consumed, filtered);// send to all application event filters (only does anything in the main thread)if (QCoreApplication::self&& receiver->d_func()->threadData.loadRelaxed()->thread.loadAcquire() == mainThread()&& QCoreApplication::self->d_func()->sendThroughApplicationEventFilters(receiver, event)) {filtered = true;return filtered;}// send to all receiver event filtersif (sendThroughObjectEventFilters(receiver, event)) {filtered = true;return filtered;}// deliver the eventconsumed = receiver->event(event);return consumed;
}
延迟删除的核心(个人理解)
- 1: 就是通过记录looplevel 和 eventlevel 然后在条件比较两者
- 2:eventLevel 是每个事件中的一个快照相当于curentlevel, 他记录的是当前looplevel, 而looplevel 是不断变换的。相当于looplevel 是一个动态的全局或者静态的变量, eventLevel 是每个事件中的一个属性
场景1:主循环中的延迟删除
// loopLevel = 0 (初始)
QCoreApplication::exec(); // loopLevel → 1QObject* obj = new QObject;
obj->deleteLater(); // eventLevel = 1// 事件处理时:
// eventLevel=1, loopLevel=1 → 条件3满足 → 立即删除
场景2:嵌套循环中的跨级删除
// 主循环中 (loopLevel=1)
QObject* outerObj = new QObject;
outerObj->deleteLater(); // eventLevel=1QEventLoop nestedLoop;
// 进入嵌套循环 (loopLevel=2)// 处理outerObj的延迟删除事件:
// eventLevel=1, loopLevel=2
// 1 > 2? false
// !1 && 2>0? false
// 事件非DeferredDelete → 不满足条件 → 跳过删除