[Qt]使用 QTimer::singleShot 导致的一次程序崩溃

代码

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
}

看起来好像就是在这里释放了自己

相关推荐
用户805533698033 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner3 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz8 天前
QML Hello World 入门示例
qt
xcyxiner11 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner12 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner12 天前
DicomViewer (添加模型类)3
qt
xcyxiner13 天前
DicomViewer (目录调整) 2
qt
xcyxiner13 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
桥田智能15 天前
桥田智能 QT-650S:面向白车身焊装的 800kg 重载快换解决方案
开发语言·qt·系统架构
森G15 天前
75、服务器源码解析---------云视频服务项目
linux·服务器·网络·c++·qt