How to deal with deleted slot object
-
main thread has object A function member aa(). It is a slot function connecting to worker thread object B signal bb(). Now bb() is triggered by another object C signal cc() in worker thread, but main thread just deleted object A, I got first-class exception at QMetaObject::activate().
Can't Qt gracefully handle this case if slot object is deleted, just do not trigger slot function??
How can I fix this issue? seems Mutex can't fix my problem, because all those are signal slots rather than direct function calls so Mutex will just unlock once it is out of scope. -
I have another crash case, object A function member aaa(). It is callback function called by worker thread object B function bbb(). The callback is established by boost::bind() and boost::function().
Now bbb() is triggered by another object C signal ccc() in worker thread, but main thread just deleted object A, bbb() will still call aaa(), at this moment I can see object A this pointer is not reinitialized, aaa() function pointer is not reinitialized but all its data members are reinitialized to 0xfeeefeee. so it crashes inside aaa() when using those data members.
Although here it is a boost function pointer issue, I feel it is very similar to the issue I mentioned above.
What's the good solution?
Thanks,
-
When a QObject is destroyed all of the pending events are dropped and all connections are disconnected automatically so there's no problem there. Also look at the docs on the "QObject destructor":http://doc.qt.digia.com/qt/qobject.html#dtor.QObject, it might be just your case.
It sounds more like you lost track of pointers validity across threads.
The best thing to do would be to rethink and maybe simplfy your app execution flow.But if that is not an option you can take a look at a QPointer - it's a wrapper class around QObject pointers that automatically gets set to 0 when a pointed object is destoyed.
-
Krzysztof Kawa, thank you very much. I got some hint from your post. In my case, object A and object B are highly related. class A has a class-B-type pointer as a data member. A's destructor will emit signal to inform worker thread to delete B. Note B has to be deleted in worker thread since it's created there.
@ A::~A() {
if(b_ptr != NULL) {
emit DeleteB(b_ptr);
b_ptr = NULL;
}
}@@ wokerThread::OnDeleteB(b) { delete b; }@
Based on your post, I think I should not call "delete b" directly in wokerThread::OnDeleteB(). because it is possible that C's signal is already emitted and the pending event is waiting to be delivered.
But how about my second crash case of boost::function? I can see boost is using object A pointer to call the callback function (as boost calls a_ptr->aaa()). In debugging build, that pointer is not reinitialized to 0xfeeefeee, but all its data members are reinitialized.
-
It is hard to understand the problem, without more information.
Keep in mind that:- An object should be destroyed in its own thread.
- If you add your slots in a QThread, they will be executred in the parent thread, because the QThread object does not live in itself. Adding slots to a QThread is not recommended.
- Qt alreay provide a slot to delete objects, it is the QObject::deleteLater slot. You can connect directly to that slot if you wish.