How to free an object after all slots were executed in Qt? - c++

I am facing an issue with Qt's signal and slot concept, as it is working asynchronously. I'm currently passing a pointer to an object which is created right before emitting a signal. I need to do this, because all receiving slots should use this object and be able to use the same state. I'm now running into problems, because I can't find a way to free the object after all the connected slots were executed. Is there an option for this?

You can use QSharedPointer. It will destruct automaically the object its holding when no one is referencing it anymore.

Related

Will the connection be disconnected in Qt automatically?

From the problem here: Qt Signals and Slots object disconnect? If I first call the delete on a QObject, then I call the disconnect function like this:
MyQClass* A = new MyQClass();
connect(A,SIGNAL(A_S()),this,SLOT(B_S()));
A->deleteLater();
...
disconnect(A,SIGNAL(A_S()),this,SLOT(B_S()));
Will this cause a crash? I found it cause a crash under Qt4, but not Qt5?
Is the different Qt version doing something different? Otherwise, there might be something else wrong with my code.
Connections are disconnected automatically on object destruction. The crash probably happens because you are trying to call disconnect on an object that was destroyed. You are getting a dangling pointer A (having an address to an object that does not exist anymore). But this depends a little an what "..." is.

life time of object associated with signal

Here is my sample qt connect statement
connect(pHttpFetch, SIGNAL(Fetched(QByteArray)), this, SLOT(PrintData(QByteArray)));
Here the signal of first object is connected to the slot of the invoking(which makes the connect call) object.
I have the following things
The first object is a local object. The object is killed when control goes out of scope.
The invoking object will stay in memory throughout the application memory.
As I don't need the first object, is it fine to make it a local object ? ( I assume Qt magically keeps the object in memory)
Should I make a shared pointer to hold the object. Will destroy the object when not required ?
According to the Qt documentation
All signals to and from the object are automatically disconnected, and any pending posted events for the object are removed from the event queue.
And no, Qt doesn't "magically" keep the object in memory.
An object that doesn't exist anymore can't send signals. You should allocate memory for this object and keep a reference to it. Remember that if you gave your QObject a parent, then this parent will automatically handle the deletion of their child (but if you don't provide a parent, you'll have to delete it manually or use the deleteLater() slot of QObject)

Marshal calls to Qt main thread

I'm wrapping libcommuni, which uses Qt, in a different DLL project, which doesn’t use Qt. As far as I’ve been able to tell, I need to run the Qt message pump (via QCoreApplication) to make sure networking, signals, etc. work properly. However, I’m running in to some problems figuring out how to do just that.
Basically, I want to spin up a thread in the DLL, which calls QCoreApplication::exec() and pumps all the Qt events. I then want to marshal external calls to the DLL, which are on a different thread, to the Qt main thread, so I can safely use libcommuni.
It looks like the recommended approach is to use signals and slots for this, but I’ve been unable to get that to work. I create a signal on the QObject class that is called via the DLL and I connect it to a slot on the QThread that runs the Qt message pump. However, if I specify Qt::QueuedConnection when connecting the signal and slot, the message is never delivered when I emit the signal. If I omit Qt::QueuedConnection altogether, the slot is called immediately on the calling thread rather than the Qt main thread.
I’ve also tried explicitly calling QCoreApplication::postEvent() on the DLL thread to send an event to the Qt main thread, but event(QEvent) is never called in the target QThread.
Any ideas on what I’m doing wrong here? I'm guessing I'm not quite understanding Qt's threading model.
When you use QObject::connect without specifying connection type - it uses Qt::AutoConnection, which turns into Qt::DirectConnection if the signal and slot are in a single thread, or into Qt::QueuedConnection, if they are in different threads. So, in your case, I can say, that for the moment, when you connect your signal with your slot, the objects, they belong to, are located in one thread.
In order to make Qt::QueuedConnection work, you need an event loop in a thread, which contains slot.
There are two main ways of using QThread:
You can derive QThread and rewrite QThread::run. In that case you should do several things:
When creating your thread's object, do not specify parent; remove this object manually.
In your thread's constructor call moveToThread(this).
In your thread's run method call exec after all initialization, but before all removal; thread will leave exec right after you call QThread::quit.
You can derive QObject, create QThread object, and call QThread::moveToThread on your object (which, by the way, should be created without specifying parent) before calling QThread::start.
In your case I would recommend using the second method.
That is about threads, but I am not quite sure, your problem isn't connected with QCoreApplication::exec.

Calling a QObject function from QML across threads

I'm trying to determine how calling QObject slots or Q_INVOKABLE methods from QML for a QObject that lives in another thread works, and whether or not its safe to do so.
Assume there's a MainThread and ThreadA. QObjectA lives in ThreadA. The QML engine/gui/everything lives in the MainThread. I expose QObjectA to the QML engine using
declarativeView->setContextProperty("someObj",ObjectA)
Now in a QML file, I call
someObj.someMethod();
Where someMethod is a slot or is Q_INVOKABLE. I'd like to know which thread actually executes the function. If it's MainThread, that would be a bad thing, and calling a method like that across threads would be dangerous. If it was executed by ThreadA however, all would be well.
Based on this documentation: http://doc.qt.nokia.com/4.7-snapshot/qtbinding.html, I'm assuming that QMetaObject::invokeMethod() is used to call the QObject function. That documentation (http://doc.qt.nokia.com/4.7-snapshot/qmetaobject.html#invokeMethod), shows that there are different connection types available, just like with Qt signals and slots.
I'd like to know if Qt's qml engine automagically chooses the right type for the situation when invoking C++ methods from QML across threads, and if so, calling methods for objects that live in other threads from QML is an acceptable practice.
As it became apparent a while ago, QML doesn't seem to be able to go across threads.
So one needs to implement a C++ side intermediate object that lives in the main thread to dispatch calls to objects in other threads.
QML object -> object in a different thread // doesn't work!!!
QML object -> C++ mediator object -> object in a different thread // WORKS!!!
Basically, "transcending" threads must happen in C++ entirely, thus the need of a mediator object.
I guess the someMethod will be executed in ThreadA since the object lives in that thread.
But normally if this gives a problem, then I would do something like this.
connect(&threadA, SIGNAL(started()), someObj, SLOT(someMethod());
But to start that ThreadA we need one more CppObject to link QML and CPP.
You can use this->thread(); or QThread::currentThreadId(); inside the slot to get the thread the slot is working in. It will always be the thread, the ObjectA was created in (if there was no moveToThread()).
The Qt-Engine will select the right Qt:ConnectionType by determine call and called thread.
Extra tip: You can use GammaRay or ThreadSanitizer to see current direct connections across threads.
QML logic is event-driven and all invokes are parts of JavaScript functions. JS functions may be event handlers (for ex. UI event handlers) or may be invoked somewhere in C++ code if you wrap them in QScript object. Also you can invoke them in JavaScript WorkerTherad. That is why only you can provide an answer, where does someObj.someMethod() invokation take place.

Deletion of objects send by signals, Ownership of objects in signals, Qt

Here, my signal declaration:
signals:
void mySignal(MyClass *);
And how I'm using it:
MyClass *myObject=new myClass();
emit mySignal(myObject);
Here comes my problem: Who is responsible for deletion of myObject:
Sender code, what if it deletes before myObject is used? Dangling Pointer
The slot connected to signal, what if there is no slot or more than one slot which is connected to the signal? Memory Leak or Dangling Pointer
How does Qt manage this situation in its build-in signals? Does it use internal reference counting?
What are your best practices?
You can connect a signal with as many slots as you want so you should make sure that none of those slots are able to do something you would not want them to do with your object:
if you decide to pass a pointer as a parameter then you will be running in the issues you describe, memory management - here nobody can to the work for you as you will have to establish a policy for dealing with allocation/deletion. To some ideas on how to address this see the Memory Management Rules in the COM world.
if you decide to pass a parameter as a reference then you don't have to worry about memory management but only about slots modifying your object in unexpected ways. The ideea is not to pass pointers unless you have to - instead use references if you can.
if you decide to pass a const reference then, depending on your connection type, QT will pass the value of the object for you (see this for some details)
avoid any problems and pass by value :)
See also this question for some thoughts about passing pointers in signals.
For your first question, use QPointer
For your second question,
If I understood clearly, even if you are sending myObject, you still have the reference myObject in the class where you are emitting the signal. Then how will it be a memory leak or a dangling pointer? You can still access the myObject from the emitted class, isn't?
Hope am clear..
Edit :
From your comments I believe you are releasing/deleting the objects in the slots. Now I assume your problem is, what if the (memory releasing) slot gets called once,twice or not called at all.
You can use QPointer for that. From the Qt documentation,
Guarded pointers (QPointer) are useful whenever you need to store a pointer to a QObject that is owned by someone else, and therefore might be destroyed while you still hold a reference to it. You can safely test the pointer for validity.
An example from the Qt documentation itself,
QPointer<QLabel> label = new QLabel;
label->setText("&Status:");
...
if (label)
label->show();
the explanation goes on like this..
If the QLabel is deleted in the meantime, the label variable will hold 0 instead of an invalid address, and the last line will never be executed. Here QLabel will be your MyClass and label is your myObject. And before using it check for Nullity.
At 1): The sender should take care. When sending the signal synchronously (instead of queued), the object is still alive when a receiver receives it. If the receiver needs to store it, only a QPointer would help, but then MyClass needs to derive from QObject, which looks wrong from the context.
Anyway, that is a general lifetime issue, not very signal/slot-specific.
Alternatives: Use a value class and send it via const reference. If MyClass can have subclasses, pass a const QSharedPointer&
About deleteLater: deleteLater() doesn't help here. It would make queued connections any safer, and for direct connections it makes no difference. The one use where deleteLater() comes into play is if the receiver needs to delete the sender. Then one should always use deleteLater(), so the sender can complete what he was doing, which would otherwise crash.
In a word (alright, function name) - deleteLater() :) All QObjects have it. It will mark the object for deletion, and this will then happen on the next event loop update.