Reputation: 183
main.cpp:
#include <QCoreApplication>
#include <QtCore>
#include "myobject.h"
QThread* cThread;
MyObject* cObject;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
cThread = new QThread();
cObject = new MyObject();
cObject->moveToThread(cThread);
QObject::connect(cThread, SIGNAL(started()),
cObject, SLOT(doWork()));
QObject::connect(cThread, SIGNAL(finished()),
cThread, SLOT(deleteLater()));
QObject::connect(cThread, SIGNAL(finished()),
cObject, SLOT(deleteLater()));
cThread->start();
return a.exec();
}
myobject.cpp:
#include "myobject.h"
MyObject::MyObject(QObject *parent) :
QObject(parent)
{
}
void MyObject::doWork()
{
qDebug() << "Hi";
QThread::currentThread()->quit();
return;
}
myobject.h:
#ifndef MYOBJECT_H
#define MYOBJECT_H
#include <QtCore>
class MyObject : public QObject
{
Q_OBJECT
public:
explicit MyObject(QObject *parent = 0);
signals:
public slots:
void doWork();
};
#endif // MYOBJECT_H
Apparently, according to: https://stackoverflow.com/a/16062717, there is a memory leak, but how do I fix it? I guess I would have to return to the event loop and then call quit? But the issue is that I don't have access to the event loop.
Upvotes: 3
Views: 2158
Reputation: 22890
I am the poster on the link. There is in fact no memory leak with the default connection. By subclassing deleteLater and destructors like @phyatt did you obtain :
Hi
void MyObject::deleteLater()
virtual MyObject::~MyObject() Being deleted
void MyThread::deleteLater()
virtual MyThread::~MyThread() Being deleted
But If you use Qt::QueueConnection
for instance in your connections you obtain:
Hi
void MyThread::deleteLater()
virtual MyThread::~MyThread() Being deleted
And the object cObject
is leaked.
It is undocumented when the thread will effectively exit. So I cannot argue whether this behavior will always be the same. One possibility is to make the thread launcher responsible for doing the cleanup work. For instance:
void cleanup(){
cThread->exit();
cThread->wait();
delete cThread;
delete cObject;
}
To wrap things up, you don't have to fix anything with this code.
Upvotes: 0
Reputation: 19102
There isn't a memory leak. Qt does clean up properly if you stick to its object model, and object trees and ownership. I also like following the documented examples.
Here is the example you referenced, with observation added on deleteLater()
.
main.cpp
#include <QCoreApplication>
#include <QtCore>
#include <QThread>
class MyThread : public QThread
{
Q_OBJECT
public slots:
void deleteLater()
{
qDebug() << Q_FUNC_INFO;
QThread::deleteLater();
}
};
class MyObject : public QObject
{
Q_OBJECT
public:
explicit MyObject(QObject *parent = 0){}
signals:
public slots:
void deleteLater()
{
qDebug() << Q_FUNC_INFO;
QObject::deleteLater();
}
void doWork()
{
qDebug() << "Hi";
QThread::currentThread()->quit(); // It is supposed to stop here, but it doesn't.
return;
for (int i = 0; i < 1000000; i++) {
qDebug() << i;
}
}
};
QThread* cThread;
MyObject* cObject;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
cThread = new MyThread();
cObject = new MyObject();
cObject->moveToThread(cThread);
QObject::connect(cThread, SIGNAL(started()),
cObject, SLOT(doWork()));
QObject::connect(cThread, SIGNAL(finished()),
cThread, SLOT(deleteLater()));
QObject::connect(cThread, SIGNAL(finished()),
cObject, SLOT(deleteLater()));
cThread->start();
return a.exec();
}
output:
Hi
void __thiscall MyObject::deleteLater(void)
void __thiscall MyThread::deleteLater(void)
Hope that helps.
Upvotes: 1