qt QObject对象释放

本文探讨了Qt编程中关于QObject对象释放不当可能导致的崩溃和内存泄露问题。当QObject对象在事件队列仍有待处理事件时直接删除,可能会导致后续槽函数执行时的崩溃。此外,即使在QThread中调用deleteLater,如果线程循环不退出,deleteLater也无法执行,从而引发内存泄露。解决这些问题的关键在于正确使用deleteLater确保对象在所有事件处理完毕后再进行释放。
摘要由CSDN通过智能技术生成

一、坑的现象

QObject对象释放不当,会导致崩溃或者内存泄露

二、遇坑的原因

1、 如果事件队列中, 某QObject对象有事件等待未处理,直接delete后,再接着执行它的槽函数会导致崩溃
例子:

//创建一个QObject对象,并且有一个槽函数
class A : public QObject
{
    Q_OBJECT
public:
    explicit A(QObject *parent = nullptr);
    ~A()
    {
        qDebug() << "~A";
    }

public slots:
    void    sltTest();
};
//qt的线程对象
MyThread::MyThread(QObject *parent) : QObject(parent)
{
    QThread* pThread = new QThread();
    this->moveToThread(pThread);
    pThread->start();
}

void MyThread::setObject(QObject *object)
{
    m_mainObject = object;
}

void MyThread::sltRun()
{
    int n = 0;
    delete m_mainObject;
}

//main中创建对象A,创建子线程MyThread,并在子线程中运行sltRun函数,在子线程中删除对象
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    MyThread *my = new MyThread;

    A *testMainObject = new A;
    my->setObject(testMainObject);

    QTimer::singleShot(1000, [=](){
        QMetaObject::invokeMethod(my, "sltRun");
    });
//对象删除后,再往事件队列中扔一个testMainObject的槽函数,当执行这个槽函数的时候,testMainObject已经变成野指针,导致程序崩溃
    QTimer::singleShot(1000, [=](){
        QMetaObject::invokeMethod(testMainObject, "sltTest");
    });
    qDebug() << "run~~~";

    return a.exec();
}

上述代码执行后,大概率会发生崩溃现象,原因是QObject对象释放后,再继续使用,这时qt文档建议,释放QObject对象使用deleteLater()函数,deleteLater保证事件队列中该对象的槽函数执行完成后 ,再执行释放操作

2、 在QThread::run线程中,就算调用了processEvents,调用QObject对象的deleteLater函数,deleteLater也不会执行,会造成内存泄露
在上述代码的基础上在sltRun函数中添加如下代码

void MyThread::sltRun()
{
    while (1)
    {
        QThread::sleep(2);
        qDebug() << 123;

        A *a = new A;

        QMetaObject::invokeMethod(a, "sltTest");
        QMetaObject::invokeMethod(a, "deleteLater");
        a->deleteLater();
        qApp->processEvents(QEventLoop::AllEvents, 10);
    }
}

只有sltTest中的日志会打印,A对象的析构函数日志没有打印,qt官方文档是这样解释:
Note that entering and leaving a new event loop (e.g., by opening a modal dialog) will not perform the deferred deletion; for the object to be deleted, the control must return to the event loop from which deleteLater() was called
得出结论,不管QThread是用run方式还是moveToThread方式起来的,如果一直在一个函数中做循环操作如while(1),就算在循环中调用processEvents,属于该线程的普通槽函数会执行,但deleteLater不会执行,deleteLater只有在控制权限回到事件队列中,才会执行,这样就导致如果线程的run函数或者sltRun中一直不终端,并且不停地调用deleteLater,就会有内存泄露发生,程序内存会不断的增长,且很难发现

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值