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

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

相关推荐
xMathematics3 小时前
计算机图形学实践:结合Qt和OpenGL实现绘制彩色三角形
开发语言·c++·qt·计算机图形学·cmake·opengl
星火撩猿5 小时前
ubantu中下载编译安装qt5.15.3
开发语言·qt
机器视觉知识推荐、就业指导8 小时前
开源QML控件:进度条滑动控件(含源码下载链接)
前端·qt·开源·qml
꧁坚持很酷꧂12 小时前
Linux Ubuntu18.04下安装Qt Craeator 5.12.9(图文详解)
linux·运维·qt
ChoSeitaku12 小时前
17.QT-Qt窗口-工具栏|状态栏|浮动窗口|设置停靠位置|设置浮动属性|设置移动属性|拉伸系数|添加控件(C++)
c++·qt·命令模式
OpenC++15 小时前
【C++QT】Buttons 按钮控件详解
c++·经验分享·qt·leetcode·microsoft
我真的不会C16 小时前
QT窗口相关控件及其属性
开发语言·qt
云小逸17 小时前
【QQMusic项目界面开发复习笔记】第二章
c++·qt
꧁坚持很酷꧂17 小时前
配置Ubuntu18.04中的Qt Creator为中文(图文详解)
开发语言·qt·ubuntu
快乐飒男18 小时前
Qt基础009(HTTP编程和QJSON)
qt