Discussion:
[Interest] How to get destructor called in object that was moved to a thread?
Murphy, Sean
2015-08-17 21:34:17 UTC
Permalink
I'm struggling to get my destructor called in a class of mine that is moved to a separate thread

In my class's header file:
class myClass
{
Q_OBJECT
...
}

In my class's .cpp file:
myClass::~myClass()
{
qDebug("myClass destructor");
}

MainWindow.h:
QThread* myThread;
myClass* mine;

My mainwindow's .cpp file:
MainWindow::MainWindow(QWidget *parent)
{
mine = new myClass();
myThread = new QThread(this);
mine->moveToThread(myThread);
myThread->start();
}

MainWindow::~MainWindow()
{
myThread ->exit();
delete ui;
}

When I run my application, myClass functions properly, signals and slots in it are being called. But when the user clicks the MainWindow's 'X' button to close the application, the destructor for my class is never called, or at least that qDebug() statement is never printed to the console.

Any thoughts?
Allan Sandfeld Jensen
2015-08-17 21:44:05 UTC
Permalink
Post by Murphy, Sean
I'm struggling to get my destructor called in a class of mine that is moved
to a separate thread
class myClass
{
Q_OBJECT
...
}
myClass::~myClass()
{
qDebug("myClass destructor");
}
QThread* myThread;
myClass* mine;
MainWindow::MainWindow(QWidget *parent)
{
mine = new myClass();
myThread = new QThread(this);
mine->moveToThread(myThread);
myThread->start();
}
MainWindow::~MainWindow()
{
myThread ->exit();
delete ui;
}
When I run my application, myClass functions properly, signals and slots in
it are being called. But when the user clicks the MainWindow's 'X' button
to close the application, the destructor for my class is never called, or
at least that qDebug() statement is never printed to the console.
Any thoughts?
Where do you delete mine? I see no delete nor any ownership. Note that unless
you move it back you need to delete it from the body of the new thread. If the
new thread has a runloop you can also async call the slot mine->deleteLayer().

`Alla
Murphy, Sean
2015-08-19 02:15:48 UTC
Permalink
Post by Allan Sandfeld Jensen
Where do you delete mine? I see no delete nor any ownership. Note that
unless you move it back you need to delete it from the body of the new
thread. If the new thread has a runloop you can also async call the slot mine-
Post by Allan Sandfeld Jensen
deleteLayer().
Yeah, I mistakenly assumed that the moveToThread() call would cause the QThread object to take
ownership of the "mine" object. So I've got that fixed now using Thiago's suggestion in the response
following yours.

Thanks,
Sean
Reinhardt Behm
2015-08-19 03:26:42 UTC
Permalink
Post by Murphy, Sean
Post by Allan Sandfeld Jensen
Where do you delete mine? I see no delete nor any ownership. Note that
unless you move it back you need to delete it from the body of the new
thread. If the new thread has a runloop you can also async call the slot
mine->
Post by Allan Sandfeld Jensen
deleteLayer().
Yeah, I mistakenly assumed that the moveToThread() call would cause the
QThread object to take ownership of the "mine" object. So I've got that
fixed now using Thiago's suggestion in the response following yours.
If this would be the case it would also not what you wanted because the
QThreat object does not live in the thread. It only manages it.
--
Best Regards

Reinhardt Behm
Allan Sandfeld Jensen
2015-08-19 10:08:44 UTC
Permalink
Post by Murphy, Sean
Post by Allan Sandfeld Jensen
Where do you delete mine? I see no delete nor any ownership. Note that
unless you move it back you need to delete it from the body of the new
thread. If the new thread has a runloop you can also async call the slot mine-
Post by Allan Sandfeld Jensen
deleteLayer().
Yeah, I mistakenly assumed that the moveToThread() call would cause the
QThread object to take ownership of the "mine" object. So I've got that
fixed now using Thiago's suggestion in the response following yours.
I trick I often use for QThread. Since the concept of having a single
interface to the job you are doing in the thread often makes sense, but you
can't have it in QThread (because QThread does not live in itself), you can
have a second object that IS living in the new QThread. You can call this
MyJob or MyThreadMain, or whatever. This can then be owned by a smart pointer
(QScopedPointer) inside QThread::run, and all qobjects that live in the thread
and that needs to be deleted on thread exit can have this object as their
parent. Also you can use signals and slots on the object to asynchronously
feed the job with data and get results back from it. Since it is owned by
another thread the signal will automatically become queued.

Just remember it can not be the QThread itself :)

`Allan

Thiago Macieira
2015-08-17 22:00:20 UTC
Permalink
Post by Murphy, Sean
I'm struggling to get my destructor called in a class of mine that is moved
to a separate thread
You must call it in the thread that the object is associated with.
Post by Murphy, Sean
MainWindow::MainWindow(QWidget *parent)
{
mine = new myClass();
myThread = new QThread(this);
mine->moveToThread(myThread);
myThread->start();
}
You have two options:

delete it in the myThread thread once you no longer need it. You can also
connect its destroyed() signal to the thread's quit() slot, so the thread will
Post by Murphy, Sean
MainWindow::~MainWindow()
{
myThread ->exit();
Replace the line above with
mine->deleteLater();
myThread->wait();
Post by Murphy, Sean
delete ui;
}
The other option is to move the object back to the main thread before exiting
that thread, and then deleting it in the destructor once the thread has
exited. This is a lot harder and, as far as I can tell, unnecessary.
--
Thiago Macieira - thiago.macieira (AT) intel.com
Software Architect - Intel Open Source Technology Center
Murphy, Sean
2015-08-19 02:10:17 UTC
Permalink
Post by Thiago Macieira
Post by Murphy, Sean
I'm struggling to get my destructor called in a class of mine that is
moved to a separate thread
You must call it in the thread that the object is associated with.
Post by Murphy, Sean
MainWindow::MainWindow(QWidget *parent) {
mine = new myClass();
myThread = new QThread(this);
mine->moveToThread(myThread);
myThread->start();
}
delete it in the myThread thread once you no longer need it.
That's not an option without subclassing QThread though right? Since the way I'm doing it, the only object
that is lives in the myThread thread is the object I'm trying to delete. Or am I misunderstanding something?
Post by Thiago Macieira
You can also
connect its destroyed() signal to the thread's quit() slot, so the thread will
Post by Murphy, Sean
MainWindow::~MainWindow()
{
myThread ->exit();
Replace the line above with
mine->deleteLater();
myThread->wait();
Post by Murphy, Sean
delete ui;
}
This seemed to do the trick.
Post by Thiago Macieira
The other option is to move the object back to the main thread before
exiting that thread, and then deleting it in the destructor once the thread has
exited. This is a lot harder and, as far as I can tell, unnecessary.
Then I'll avoid it!

Thanks,
Sean
Loading...