Is there method that gets called just before object destroyed? So I can override it.
Like
protected override function beforeDestuction():void
{
trace("This object is about to be destroyed!");
}
No, there are no destructors in actionscript, unfortunately.
If by destroyed you mean getting garbage-collected, then I don't think there's an event or a Object method for that.
This won't apply to all objects, but when looking at components that extend UIComponent, the 'remove' event can be somewhat usefull, assuming there are no other strong references to a removed object it should be garbage collected.
UIComponent.html#event:remove
One way to know whether an object will be garbage collected is to hold references in a Collection to all the objects that you allocate memory for. Then when you want the GC to destroy them, then take them out of the Collection. When you take them out of the collection, call your method "beforeGarbageCollection" or "beforeDestruction"; hopefully soon (but no guarantees) the GC will pick up the unreferenced object and destroy it.
Let me know if this is suitable.
Related
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.
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.
I'm having a memory management problem and I'm wondering if it's related to how I add and remove event listeners. Let's say I have something like the following in a function:
ns = new NetStream();
addEventListener(NetStatusEvent.NET_STATUS,handleStatus);
If I were to call it again, does the fact that I'm recreating ns with "new" remove any listeners that were attached to the object?
No, the new keyword will not mark former instances for garbage collection as the event listener attached to the old instance of ns retains the object in memory.
Assuming you mean:
ns = new NetStream();
ns.addEventListener(NetStatusEvent.NET_STATUS, handleStatus);
Instance of ns is now retained by the event listener itself.
ActionScript 3.0 Reference for the Adobe Flash Platform: addEventListener()
If you no longer need an event listener, remove it by calling
removeEventListener(), or memory problems could result. Event
listeners are not automatically removed from memory because the
garbage collector does not remove the listener as long as the
dispatching object exists (unless the useWeakReference parameter is
set to true).
Ideally remove the event listener when you dispose the object:
ns.removeEventListener(NetStatusEvent.NET_STATUS, handleStatus);
Otherwise, you could implement your event listeners using weak references:
ns.addEventListener(NetStatusEvent.NET_STATUS, handleStatus, false, 0, true);
Weak reference determines whether the reference to the listener is strong or weak. A strong reference (the default) prevents your listener from being garbage-collected. A weak reference does not.
The statement ns = new NetStream(); may or may not result in the eventual removal of event listeners. If the variable ns held a reference to another object before the assignment, and this was the last reference to that object, the garbage collector may at some point destroy the object. The event listeners attached to the old object won't affect its destruction. If an object is destroyed, all of its event listeners are removed, and, if the aren't any remaining references to the listeners, the listeners can be destroyed, too (this only applies to inner functions, member functions are never destroyed).
Note that it might take some time until the garbage collector destroys objects. So even an unreferenced object will continue to fire events. This is why it's usually a good idea to remove event listeners if you're done with an object.
I have some objects created in QML code with
Qt.createQmlObject (...)
How can I delete/remove these objects?
something = Qt.createQmlObject (...);
something.destroy();
Take a look at this article:
Dynamic Object Management in QML
and on this part especially:
Note that it is safe to call destroy() on an object within that
object. Objects are not destroyed the instant destroy() is called, but
are cleaned up sometime between the end of that script block and the
next frame (unless you specified a non-zero delay).
I have an httpservice object instantiated and have defined an event listener to handle the result.
e.g.
http.addEventListener(ResultEvent.RESULT,function (event:ResultEvent):void {
// handle result
// ...
//should I remove this anonymous event listener?:
event.currentTarget.removeEventListener(event.type, arguments.callee);
});
I'm only curious from an efficiency/best practice point of view.
Depends if you're going to reuse it, and/or if you need closure variables from the current scope. If there's no reuse, then data-hiding might suggest making it local or at least private. If it's something that's going to be reused, or something that might even be overridden by a subclass, then make it separate and protected.
My 2 cents.
Update:
Whoops, I thought the question was whether the listener should be anonymous or not.
You should definitely remove any listener, anonymous or not, if it's no longer needed. Otherwise, it's useless cpu usage if the event keeps firing.