【问题标题】:Exception safety guarantee of QCoreApplication::postEventQCoreApplication::postEvent的异常安全保证
【发布时间】:2014-05-15 10:03:44
【问题描述】:
我正在使用此代码发布活动:
QEvent*event=new QEvent(QEvent::User);
QCoreApplication::postEvent(pointerToSomeQObject,event);
QCoreApplication::postEvent 描述为here。但是,如果在 postEvent 中引发异常,绝对没有关于我应该做什么的信息。
我认为该功能属于以下四类之一:
- 它从不抛出异常(特别是没有 std::bad_alloc)
- 如果它抛出它永远不会删除事件。
- 如果它抛出它有时会删除事件。
- 如果它抛出它总是会删除事件。
最坏的情况是第三种情况。
所以:如果 postEvent 抛出,我需要删除事件吗?
【问题讨论】:
标签:
c++
qt
qt5
exception-safety
【解决方案1】:
我找到了 QApplication::postEvent 的代码:
void QCoreApplication::postEvent(QObject *receiver, QEvent *event, int priority)
{
if (receiver == 0) {
qWarning("QCoreApplication::postEvent: Unexpected null receiver");
delete event;
return;
}
QThreadData * volatile * pdata = &receiver->d_func()->threadData;
QThreadData *data = *pdata;
if (!data) {
// posting during destruction? just delete the event to prevent a leak
delete event;
return;
}
// lock the post event mutex
data->postEventList.mutex.lock();
// if object has moved to another thread, follow it
while (data != *pdata) {
data->postEventList.mutex.unlock();
data = *pdata;
if (!data) {
// posting during destruction? just delete the event to prevent a leak
delete event;
return;
}
data->postEventList.mutex.lock();
}
QMutexUnlocker locker(&data->postEventList.mutex);
// if this is one of the compressible events, do compression
if (receiver->d_func()->postedEvents
&& self && self->compressEvent(event, receiver, &data->postEventList)) {
return;
}
if (event->type() == QEvent::DeferredDelete && data == QThreadData::current()) {
// remember the current running eventloop for DeferredDelete
// events posted in the receiver's thread
static_cast<QDeferredDeleteEvent *>(event)->level = data->loopLevel;
}
// delete the event on exceptions to protect against memory leaks till the event is
// properly owned in the postEventList
QScopedPointer<QEvent> eventDeleter(event);
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();
}
在异常情况下使用 RAII QScopedPointer 守卫销毁事件是非常小心的。
我猜我的问题的答案是第四个选择:
如果它抛出它总是会删除给定的事件。