[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
}

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

相关推荐
走好每一步18 小时前
1、VTK+QT + cmake编程 三维圆柱体
qt·vtk
小小码农Come on21 小时前
Qt::WA_StyledBackground属性的作用
开发语言·qt
秋田君21 小时前
2026 前端新出路:掌握 C++ 核心语法,无缝衔接 QT 桌面开发
前端·c++·qt
走好每一步1 天前
0、VDK编译 CMake + VS2017 x64
qt·vtk·三维图像
雪的季节1 天前
Qt多窗口架构设计需求简介
开发语言·qt
jingshaoqi_ccc1 天前
windows 10系统下QT的安装及在Visual studio中的扩展安装
windows·qt·visual studio
Starry-sky(jing)1 天前
# Linux 下 Qt 应用无障碍自动化:记一次wx无人值守系统的架构演进
linux·qt·自动化
必须得开心呀2 天前
QT 5.11.1使用QMetaObject::invokeMethod调用函数失败,提示提示 “no such method ***”
qt
誰能久伴不乏2 天前
工业级 Modbus 上位机架构:基于滴答引擎与状态锁的高并发调度器
c++·qt·架构
代钦塔拉2 天前
Qt信号槽参数类型全解:原生类型、结构体、enum class强枚举注册与传参实战
开发语言·qt