代码
cpp
void Widget::on_pushButton_clicked()
{
QString str = "sing jump rap";
QTimer::singleShot(5000, this, [&](){
str = QStringLiteral("唱 跳 rap");
qDebug() << "str : " << str;
});
}
简单推测就是 QTimer::singleShot
当定时到了时,访问了已经释放的对象导致的。
思考
QTimer::singleShot
是如何实现的
cpp
void QTimer::singleShotImpl(int msec, Qt::TimerType timerType,
const QObject *receiver,
QtPrivate::QSlotObjectBase *slotObj)
{
if (msec == 0) {
bool deleteReceiver = false;
// Optimize: set a receiver context when none is given, such that we can use
// QMetaObject::invokeMethod which is more efficient than going through a timer.
// We need a QObject living in the current thread. But the QThread itself lives
// in a different thread - with the exception of the main QThread which lives in
// itself. And QThread::currentThread() is among the few QObjects we know that will
// most certainly be there. Note that one can actually call singleShot before the
// QApplication is created!
if (!receiver && QThread::currentThread() == QCoreApplicationPrivate::mainThread()) {
// reuse main thread as context object
receiver = QThread::currentThread();
} else if (!receiver) {
// Create a receiver context object on-demand. According to the benchmarks,
// this is still more efficient than going through a timer.
receiver = new QObject;
deleteReceiver = true;
}
QMetaObject::invokeMethodImpl(const_cast<QObject *>(receiver), slotObj,
Qt::QueuedConnection, nullptr);
if (deleteReceiver)
const_cast<QObject *>(receiver)->deleteLater();
return;
}
new QSingleShotTimer(msec, timerType, receiver, slotObj);
}
可见当 msec
不为零时,会创建一个 QSingleShotTimer
的对象,既然是 new 一个对象,那么这个对象是什么时候删除的,
cpp
void QSingleShotTimer::timerEvent(QTimerEvent *)
{
// need to kill the timer _before_ we emit timeout() in case the
// slot connected to timeout calls processEvents()
if (timerId > 0)
killTimer(timerId);
timerId = -1;
if (slotObj) {
// If the receiver was destroyed, skip this part
if (Q_LIKELY(!receiver.isNull() || !hasValidReceiver)) {
// We allocate only the return type - we previously checked the function had
// no arguments.
void *args[1] = { nullptr };
slotObj->call(const_cast<QObject*>(receiver.data()), args);
}
} else {
emit timeout();
}
// we would like to use delete later here, but it feels like a
// waste to post a new event to handle this event, so we just unset the flag
// and explicitly delete...
qDeleteInEventHandler(this); //里面就是 delete this
}
看起来好像就是在这里释放了自己