When to use deleteLater - qt

Assuming I have the following snippet, is it safe to call deleteLater in qto's destructor for other QT objects it might administer?
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyQTObject qto;
qto.show();
return a.exec();
}
Because I've analyzed similar code like this with a leak detector and all the objects for which deleteLater was called, weren't deallocated correctly unless I replaced the call with a normal delete.
If I've understood this correctly, deleteLater only registers a deletion event in the QT message queue. Can this be the problem that qto's destructor is called at the end of main's scope whereas the QT message loop already ends with the return from a.exec? Thus the deletion event will never be processed, in fact not even pushed into a message queue since there is none?

This post is rather aged, but I would like to add the answer I would have liked to come across when I was asking this myself.
deleteLater() can be very useful in combination with asynchronous operations. It especially shines, I think, with the more recent possibility to connect signals to lambda functions.
Suppose you have some longComputation() that you want to execute asynchronously (not in the sense of multithreading, in the sense of scheduling execution in the event loop). You can do like this:
void MyClass::deferLongComputation()
{
QTimer* timer = new QTimer();
connect(timer,
&QTimer::timeout,
[this, timer](){this->longComputiation(); timer->deleteLater();});
timer->setSingleShot(true);
timer->start();
}
where deleteLater() takes care of safely disposing of the QTimer once its duty has been carried out and avoid the memory leak that one would have otherwise.
The same pattern can be used in multithreading with QFutureWatcher.

As I understand it, deleteLater is most often used when you require an object to be deleted from within the call to a slot. If delete is used in this case and the object is referenced when returning from the slot, a reference to uninitialised memory occurs.
Therefore, deleteLater requests that object to be deleted by placing a message on the event loop, which is processed at some point, on returning from the slot and it is safe to be deleted.
I expect that using deleteLater in the destructor means there's a likely chance that the object goes out of scope, calls deleteLater on its managed objects, but quits before the event loop has a chance to delete the objects, as exiting from QApplication::exec() will terminate the event loop.

The question is old, but I'll leave this for the future generation)
The reply which was marked as an answer is correct but oddly formulated.
Actually your question contains a right answer:
message loop already ends with the return from a.exec? Thus the
deletion event will never be processed, in fact not even pushed into a
message queue since there is none.
This is exactly what is happening. Everything deleteLater() does is just posting a deletion event into the outter event loop. When event gets proccessed - object gets deleted. But if there are not outter event loop and no event loop is encountered later in the execution flow - event will never get posted, thus object is never deleted.
If you call deleteLater() in the object's destructor and put an object on the stack - deleteLater() is called when the object goes out of scope. In your example "going out of scope" is happening when closing brace of main() function is encountered. However, by that time, a.exec() (which represents the main event loop of Qt App) has already returned --> no event loop any more --> deleteLater() was called, but it's nowhere to post a deletion event --> objects were supposed to be "deletedLater" never get deleted...
Regarding the part "when to use deleteLater()":
Kuba Ober answered:
Generally speaking, there is a narrow set of circumstances where
deleteLater should be used. Most likely you simply shouldn't be using
it...
Don't listen to it, it is absolutely incorrect as the whole answer. What you should do and what should not you better decide after reading this article. Although, it is mainly about Qt threads, the article also tells about ascynchronous programming (and, as Emerald Weapon mentioned, it is exactly what deleteLater() was created for).
Also, smart pointers and QObject parent ownership have nothing to do with scheduling for the deletion with deleteLater(). These both techniques are actually using a simple delete operation under the hood. And as the article shows and as Emerald Weapon's answer demonstrated: delete does not solve the problems deleteLater() does. So if you need to delete object you use delete, if you need to schedule it for the deletion you use deleteLater().
BTW, if you want to use smart pointer with deleteLater() you can specify the deleter:
// Shared Pointer
QSharedPointer<MyObject> obj =
QSharedPointer<MyObject>(new MyObject, &QObject::deleteLater);
// Scoped Pointer
QScopedPointer<MyObject, QScopedPointerDeleteLater> customPointer(new MyObject);
And at last, It is an NOT an error to use deleteLater() in the destructor of QObject, for non-child objects.

You are correct that the deleteLater() command is only executed by an event loop.
From the Qt documentation for QObject:
Schedules this object for deletion.
The object will be deleted when control returns to the event
loop. If the event loop is not running when this function is
called (e.g. deleteLater() is called on an object before
QCoreApplication::exec()), the object will be deleted once the
event loop is started. If deleteLater() is called after the main event loop
has stopped, the object will not be deleted.
Since Qt 4.8, if deleteLater() is called on an object that lives in a
thread with no running event loop, the object will be destroyed when the
thread finishes.
Note that entering and leaving a new event loop (e.g., by opening a modal
dialog) will \e not perform the deferred deletion; for the object to be
deleted, the control must return to the event loop from which
deleteLater() was called.
Note: It is safe to call this function more than once; when the
first deferred deletion event is delivered, any pending events for the
object are removed from the event queue.
If you want all child QObjects to be deleted when qto is deleted, make sure they are created with qto as a the parent.

Generally speaking, there is a narrow set of circumstances where deleteLater should be used. Most likely you simply shouldn't be using it.
It is an error to use it in the destructor of QObject, for non-child objects. As you've found QObjects may well be destructed without an event loop present. There are no deleteLater calls in object destructors the qtbase Qt module, for example.
One has to be careful here: for example, ~QTcpServer() invokes close() invoking d->socketEngine->deleteLater(), but the socket engine is already a child of the server and will be deleted by ~QObject() anyway.
For all I know, MyQTObject should be doing one of the following:
using a smart pointer like QScopedPointer or std::unique_ptr,
have the objects as regular (non-pointer) members,
use raw pointers and have the objects be children of it.

Related

How to avoid segfault after calling deleteLater on pointer?

I have a GraphicsScene:public QGraphicsScene inherited class with a single QGraphicsView looking at it and QTimer, ticking to call function
void GraphicsScene::adv()
{
if (actor)
views().at(0)->ensureVisible(actor,200,100);
advance();
}
advance() is an overriden method which is send to all QGraphicsItem objects on scene. The point of this function - I want to make sure actor is always visible.
actor is a unit:public QGraphicsPixmapItem object on GraphicsScene.
At some point in actor method I call deleteLater().
The next timer tick I receive SEGFAULT at views().at(0)->ensureVisible(actor,200,100); line
I wonder, why if (actor) passes as true after deleteLater() and what is the correct condition should I use?
I have an object being asynchronically deleted by deleteLater()
and wonder if there is a way to prevent accessing it from other
objects?
Yes, there is a way to tell programmatically whether or not the object was already deleted by using QPointer<MyQObject> as described. But that way is somewhat slow and your application code should rather have better logic to avoid that. Like, before calling deleteLater your code removes the reference for that object from, say, views() and your code should check for the view still there.
If you call deleteLater() from inside your actor, the container GraphicsScene still has its pointer on it - the object itself doesn't reset all external pointers to it.
You have to reset this pointer - the member actor of your GraphicsScene to get your if-statement in adv() working.

Direct connection and event loop [duplicate]

This question already has answers here:
Qt signals (QueuedConnection and DirectConnection)
(3 answers)
Closed 8 years ago.
I have read the doc of Qt and have the following question:
if I have:
class_A::on_button_click(){
...do some things...//no signal emit this part
emit signal_A();
}
class_B::on_signal_received(){
...do some things...//no signal emit this part
}
...
connect(class_A_object,SIGNAL(signal_A()),class_B_object,on_signal_received);
All the things here are in the main thread,
now when I click the button and trigger the first function,
the program will be executed from the first line of
class_A::on_button_click()
until the last line of
class_B::on_signal_received()
and during the process nothing else in the main thread will get the chance to be executed, is this correct?( "...do some things..." part don't emit any signals)
In other words, when is the moment that the control return to the event loop?
After finishing
class_A::on_button_click()
or
class_B::on_signal_received()
?
When your signal and slot are in the same thread (as mentioned by user3183610) your signal will be direct connection (the default for same-thread). This effectively runs similarly to a function call. The signal is not queued, but instead the slot that the signal is connected to executes immediately - so you can think of it as a direct function call to the slot.
You can, however, change this behavior by using the Qt::QueuedConnection optional parameter at the end of your connect call:
connect(class_A_object,SIGNAL(signal_A()),class_B_object,on_signal_received, Qt::QueuedConnection);
This will force the use of the queue, your signal will be queued in the event loop and then other pending signals will be executed in order (this is often more desirable then DirectConnection because you can more easily guarantee the order of events). I tend towards to use of queued connections for this reason (though I believe direct is very slightly more efficient).
So for your code there is no return to the event loop until after on_button_click(). During on_button_click() you emit the diret signal signal_x() and immediately on_signal_received() is called (by-passing the event loop), when this finishes it returns back to on_button_click() - just like a function call would :)

QThread and QML Locking Up

I have a class, audio_engine_interface, and in main.cpp, I add it to the QML thing.
viewer.rootContext()->setContextProperty("engine", engine);
In audio_engine_interface, I have a audio_engine class, which is computationally intensive—it needs to run on its own thread.
void audio_engine_interface::play()
{
QThread thread;
thread.start();
engine->moveToThread(&thread);
engine->play(); // Will use 100% of CPU
}
However, when I do this, the whole QML thread locks up, meaning I can't pause (pretty important). Am I missing something?
EDIT:
This thread won't mess up anything or access objects from other places. However, it does have a pause function that will need to be called at some point. For what it's worth, the engine is doing pitch shifting.
This is a problem: -
Qthread thread;
Creating a QThread object like this is creating it on the stack. When the function ends, the object will go out of scope and delete the QThread object.
You need to dynamically allocate the object on the heap: -
QThread* thread = new QThread;
Then remember to delete the thread, or set it to delete itself: -
//Qt 5 connect syntax
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
You should also be aware of thread affinity (the thread which an object is running on). I suggest reading this article on how to use QThread properly.
You have so many problems.
when you move to thread your object must not have a parent
your thread object is local variable so it will day immediately when udio_engine_interface::play() end execution
you are invoking you engine->play(); method directly and this means that it will be executed in current thread.
moveToThread means that slots invked by signals connected using default 5th parameter (Qt::AutoConnection) will be queued in event loop of given thread.
The easiest way to fix it is use QtConcurrent:
void audio_engine_interface::play()
{
QtConcurrent::run(engine, &EngineClass::play);
}
Depending what your engine does you should make it thread safe (use mutex locks an so on), without details it is hard to tell, what exactly you should do.

Passing QModelIndex cross Thread queued connection

WMIQuery::wmiquery(WMI::WMITable* table, const QString& query, WMI::ProgressIndicator* progressIndicator)
This is the Function signature. and I am calling it through QtConcurrent::run
QFuture<quint32> future = QtConcurrent::run(WMI::WMIQuery::wmiquery, _table, query);
The architecture is quite simple.
Expected number of rows that will be returned by the query is known.
query is ran parallelly and on each record fetch a row is added to table: WMI::WMITable*
WMI::WMITable is a Simple QObject Table Data Structure .
it emits rowsAboutToBeInserted(QModelIndex, int, int) and rowsInserted(QModelIndex, int, int) upon row addition.
On the other hand ProgressIndicator in instantiated on main thread and the table is passed to its ctor . it gets the expected total number of rows from WMI::WMIQuery::wmiquery() through ProgressIndicator::setRecordCount(quint64 count).
it has a slot rowAdded() which emits the progress out of 100 by doing some simple mathematics. In its ctor it connects
connect(_table, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(rowAdded()));
What I think. as WMI::WMIQuery::wmiquery() i running on a different thread (on QThreadPool) this connection is a cross thread queued connection . am I correct ?
I am getting the following error at runtime
QObject::connect: Cannot queue arguments of type 'QModelIndex'
(Make sure 'QModelIndex' is registered using qRegisterMetaType().)
What should I do ? as my SLOT(rowAdded()) does not require the 3 arguments of SIGNAL(rowsInserted(QModelIndex,int,int)) should I make another signal like rowInserted() and emit it whenever I am emitting rowsInserted(QModelIndex,int,int) and use this SIGNAL instead for this coinnection
You may ask why I am using model like signals like rowsInserted(QModelIndex,int,int) in the table data structure. cause I do also have a model that is connected to this table. which will also be updated row by row. however I think that is immater in this regard.
Before emitting a signal across a thread boundary with a non-trivial argument type (like QModelIndex), you must first call this:
qRegisterMetaType<QModelIndex>("QModelIndex");
That prepares Qt to be able to emit the signal across a thread boundary.
Normally you would do this in main() or somewhere that only runs once, before calling emit, but after your QApplication has been instantiated.
This is only necessary for types that are non-trivial. For example, a signal like this would not require you to call qRegisterMetaType()
signals:
void mySignal(int foo, int bar);
But a signal like this does require qRegisterMetaType():
signals:
void mySignal(QModelIndex);
For more info, see the Qt docs here: http://doc.qt.nokia.com/latest/qmetatype.html#qRegisterMetaType
I know this is rather late, but I wanted to be sure someone mentioned it: QModelIndex is not meant to be queued, for the same reason that it's not meant to be stored and used later in other ways. That is, if the model changes before you use the QModelIndex, you will get undefined behavior. If you need queued events with model indices, you should probably use QPersistentModelIndex. Not really relevant to the original question, but may be of use to someone who lands here.

Qt Direct Connection

I have created Qt tree control( and its nodes ) in different thread than the main thread. In the main thread I want to show context menu for the clicked node, so I am connectiong the actions in the menu with appropriate slots in the main thread. The connect function returns true , but slot is never executed. If I explicitly say in connect function that this is Qt :: DirectConnection then everything works fine. Why is this ?
I I create my tree in main thread, everything also works fine , without having to say that this is Qt::DirectConnection .
See the documentation here.
The default connection type, Qt::AutoConnection, is the same as Qt::DirectConnection if the signal is sent from the same thread as the receiver slot, otherwise the behaviour is the same as Qt::QueuedConnection.
In the case where you create the widget in the main thread, you basically get the same behaviour as when you explicitly specify Qt::DirectConnection.
The behaviour of Qt::QueuedConnection is to call the slot when that threads event loop regains control.
To solve your problem, make sure you have an event loop in every thread which may be receiving signals, unless you manually specify Qt::DirectConnection (which, I assume, will mean the slot is called from the same thread as the signals emitter - basically the equivelent of a normal function call).

Resources