如何让QThread在不泄漏的情况下发出堆分配的QObject?

Guy*_*zmo 5 c++ qt multithreading memory-leaks signals-slots

我的情况是我有一个QWidget派生类MyWidget,它将创建一个QThread派生类(WorkerThread)来在其run()方法中执行一些不间断的阻塞工作.结果是一个QObject派生类(DataClass)的堆分配实例,然后由MyWidget接收和处理.但是,MyWidget是一个暂时的小部件,当WorkerThread由于用户操作而仍在运行时可能会被删除.

这里有一些伪代码来说明这一点:

#include <QThread>
#include <QWidget>

class DataClass : public QObject {
    Q_OBJECT
public:
    // contains some complex data
};

class WorkerThread : public QThread {
    Q_OBJECT
public:
    virtual void run() {
        DataClass *result = new DataClass;
        doSomeReallyLongUninterruptibleWork(result);
        emit workComplete(result);
    }
signals:
    void workComplete(DataClass *);
};

class MyWidget : public QWidget {
    Q_OBJECT
public:
    void doBlockingWork() {
        WorkerThread *worker = new WorkerThread;
        connect(worker, &WorkerThread::finished, worker, &WorkerThread::deleteLater);
        connect(worker, &WorkerThread::workComplete, this, &MyWidget::processData);
        worker->start();
    }

public slots:
    void processData(DataClass *result) {
        // Do some stuff
        delete result;
        // Assuming MyWidget still exists when WorkerThread has finished, no memory has leaked
    }
};
Run Code Online (Sandbox Code Playgroud)

通常,返回工作线程结果的正确"Qt"方法是让它发出一个信号,其参数是其工作的结果,如上所示.这对于可以复制的数据来说很好,但由于结果是指向堆分配对象的指针,因此我必须小心确保释放内存.

通常不会有问题,因为自从WorkerThread完成后,我可以安全地将指向DataClass的指针传递给MyWidget,让它处理DataClass,然后释放它.

问题在于,正如我之前所说,MyWidget是暂时的,可能会在WorkerThread完成之前被销毁.在这种情况下,我如何确保DataClass的实例以某种方式被释放?

特别是,我正在寻找具有一些优雅的解决方案,这意味着它利用了Qt的功能,并且最好使它使WorkerThread保持与MyWidget的分离,以便WorkerThread不需要知道任何关于它或任何其他可能创建它的类.我也对改进我已经使用的模式的想法持开放态度.

Joh*_*est 7

使用智能指针(例如QSharedPointer)代替普通指针:

DataClass *result = new DataClass;
Run Code Online (Sandbox Code Playgroud)

应该换成

QSharedPointer<DataClass> result = QSharedPointer<DataClass>(new DataClass);
Run Code Online (Sandbox Code Playgroud)

然后,你可以安全地将它传递到某个地方而不用担心删除它.当它超出可以使用的最后一个范围时,该对象将被自动销毁.

  • 重要的是要注意,如果共享指针的引用计数在除了QObject"生命"之外的线程中变为零,则它将在错误的线程中被删除,这将导致严重破坏.所以当使用QObject的共享指针时,要非常小心线程!如果不确定,请不要使用它. (3认同)