In the following C++ code, a QML component is created using a QQmlIncubator. The Qt documentation has this snippet from here http://doc.qt.io/qt-5/qqmlincubator.html:
QQmlIncubator incubator;
component->create(incubator);
while (!incubator.isReady()) {
QCoreApplication::processEvents(QEventLoop::AllEvents, 50);
}
// Who owns 'object'? When is it deleted?
QObject *object = incubator.object();
It's my understanding that this snippet isn't totally complete, because you'd need to call delete on component. According to http://doc.qt.io/qt-5/qqmlcomponent.html#create, the QQmlComponent::create() function transfers ownership of the returned object instance to the caller. Good so far.
Now comes my question--who owns object in the snippet above? In my case, I've place the above snippet in a member function of a class, so the QQmlIncubator incubator goes out of scope, and I only hold on to component and object, which are both instance variables of their containing class, and I call delete component in the destructor. Am I cleaning up properly?
So does object belong to component? When does object get destroyed?
Update 1
See my follow-up question: Safely deleting QML component being used in StackView transition.
Short answer
You should destruct the incubated object (if the incubator finished successfully), otherwise a memory leakage occur.
How to manage ownership?
A good approach may be to transfer the ownership to an object parent using QObject::setParent, for example to the visual parent. This is also done by Qt when you construct QML objects in the traditional way:
Any object assigned to an item's data property becomes a child of the
item within its QObject hierarchy, for memory management purposes.
For convenience, the Item data property is its default property.
Reasoning
As mentioned in the QQmlComponent::create(QQmlContext *) documentation, the object ownership is transfered to the user:
The ownership of the returned object instance is transferred to the caller.
So, it is unlikely that the overloaded function QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context, QQmlContext *forContext) will keep the ownership, although it is not mentioned explicitly in the documentation. One could argue that the ownership is transferred to the QQmlIncubator object. This is indeed the case as long as the component is Loading, once it is ready the ownership is released as (implicitly) documented in QQmlIncubator::clear:
Any in-progress incubation is aborted. If the incubator is in the Ready state, the created object is not deleted.
Note that QQmlIncubator::clear is called inside the destructor of QQmlIncubator.
As currently written in your example, object destruction is currently your responsibility. Most likely you will want to take care of that by calling setParent() on object and thus passing on the responsibility to the parent item.
As you point out about component->create():
The ownership of the returned object instance is transferred to the
caller.
and the incubator gives all appearance of preserving that intention.
An experimental way to verify this would be to check the parent of object as returned from the incubator.
Another way to verify this is to look directly at the relevant source code in Qt. Here are the files for QQmlIncubator:
https://github.com/qt/qtdeclarative/blob/dev/src/qml/qml/qqmlincubator.cpp https://github.com/qt/qtdeclarative/blob/dev/src/qml/qml/qqmlincubator_p.h
https://github.com/qt/qtdeclarative/blob/dev/src/qml/qml/qqmlincubator.h
Examining those files, the only place that result is deleted is in the ::clear method:
if (s == Loading) {
Q_ASSERT(d->compilationUnit);
if (d->result) d->result->deleteLater();
d->result = 0;
}
Related
When calling C++ from QML, a QObject can be returned to qml by pointer. Before returning, I can call
QObject* qobj = m_sharedPtr.data(); // Pointer to member shared-ptr-managed object.
QQmlEngine::setObjectOwnership(qobj, QQmlEngine::CppOwnership);
return qobj;
but given that QML is garbage-collected, how can this work safely? My mental model is that QML will get the pointer and hold onto it, wrapped in some QML pointer wrapper and that pointer wrapper will eventually be GC'd. But then there's no limit to how long after the setObjectOwnership call that QML could access *qobj. (E.g., perhaps the next QML->C++ call after this one causes m_sharedPtr to go out of scope.) Does that mean QQmlEngine::CppOwnership is only safe to use when the object's lifetime is essentially infinite (e.g., a singleton)? I don't see any alternative, but haven't found any mention of this issue in any documentation.
If m_sharedPtr refers to data created in C++, qobj will have CppOwnership anyways, and you should handle it like any other C++ smart pointer (i.e. let it live as long as you actually need it).
If it was created in QML, it will have JavaScriptOwnership by default. If you then transfer ownership to C++, and it gets destroyed, it's not accessible in QML anymore.
If it is important that qobj is accessible in QML for an uncertain time, but still C++-managed, you could retreat to using raw pointers and handle the destruction yourself (e.g. by connecting to the aboutToClose() signal of a QML window).
I have a QObject subclass (registered with QML) called ToReturn and a QML singleton, defined in C++, called MySingleton. The latter provides this function:
Q_INVOKABLE ToReturn* get_toReturn() {
return new ToReturn();
}
When I call get_toReturn from QML, am I responsible for later calling destroy() on the returned object? Or is there a way to use automatic memory management for this?
Note that my ToReturn object does not logically belong to an object tree, so I pass nullptr to the parent constructor (QObject's).
It is supposed to work automatically, and objects are supposed to be deleted as soon as they are out of scope, have no parent and no references to them exist.
That being said, there are 2 caveats:
objects will rarely be destroyed as soon as the above conditions are met. They tend to linger for quite a while, unless garbage collection is forced
in more complex scenarios, objects will be deleted, even if they have parents and references to them. It is a critical bug that's been standing for almost 2 years now, unfortunately with zero work done on it. This has forced me to use manual object lifetime management, setting ownership to CPP explicitly just so objects don't go missing, which simply crashes the application
By default the object returned from your function will have QQmlEngine::JavaScriptOwnership unless you explicitly set it otherwise via:
QQmlEngine::setObjectOwnership(objectptr, QQmlEngine::CppOwnership);
EDIT: Note that the premature deletion has to do with JS ownership, so objects that are declared and created entirely in QML are also subject to it. You can set CPP ownership for such object to protect them too, and deletion of such objects can only be done from C++, preferably using deleteLater().
is it possible to use c++11 smart pointers with nodes user data? has anyone tried it before?
node->setUserData(void* usrData);
node->getUserData();
Solved:
i figured a way to store objects in a Node without having to delete theme manually(gets automatically deleted when the Node is destroyed) and it might not be the best solution but it is a solution nevertheless, it involves inheriting from cocos2d::Ref class and using nodes setUserObject(Ref* ptr)!
this is how i made it happen:
1)- make a class/struct that inherits from cocos2d::Ref class.
2)- fill it with your custom properties and methods.
3)- make sure the object calls autorelease().
struct Box : public cocos2d::Ref
{
// some properties here
Box() {
//autorelease means let other Nodes retain and release this object.
//if you don't call autorelease then the object destructor won't get called which means in turn object memory is not released.
this->autorelease();
}
~Box() {
//just to check if the object destructor is called or not.
log("=========================");
log("Box is destroyed");
log("=========================");
}
};
4)- make an object instance and put its pointer in any Node UserObject like this:
auto box = new Box;
this->setUserObject(box);// am putting it in the Layer UserObject
now the box object will be destroyed automatically whenever the Layer/Node is destroyed (no delete is needed)
PS: you should properly exit the cocos2d-x app in order for the nodes(Node, Layer, Scene) destructors to be called so can nodes children be destructed properly(children destructors are called) ... just press the back button if your in an emulator or use a close button that calls Director::end().
This was a comment, but got too long.
I wouldn't see it as hopeless as #Joachim Pileborg does in the comments (although his points are true in principle). The only thing you have to assume is that setUserData is only observing, i.e. it performs no memory-related actions and particularly no delete.
You can then either simply use a smart pointer "outside",
auto ptr = std::make_unique<some_object>();
node->setUserData(ptr.get());
Now, if the program then exits in a proper way, at least you don't have to manually delete ptr. But, as mentioned by Joachim, of course you have to make sure that ptr lives as long as it is might be used inside node.
Alternatively, you can write small wrapper around the node class which contains a shared_ptr<void> ptr variable and which offers a setUserData(shared_ptr<void>) method. If this method is invoked, it first copies the shared pointer and internally calls node->setUserData(ptr.get()) method. Then the underlying object is guaranteed to stay alive.
Edit
I suppose the code below would assume I have an overloaded version of addChild() that accepts a Sprite already wrapped in a unique_ptr, where taking ownership would be fine. Just thought I'd mention that before someone else did. :) . I made up all the code here after a very long day, so please take it as pseudo code quality meant only to demonstrate the issue at hand.
Original Question
I'm writing a framework where there is a display list, parents/children etc. I'm thinking that using unique_ptr<Sprite> for example is the way to go here, since when you add a child to a parent display object, it's only logical that the parent now becomes the sole owner of that child.
However, there will be methods available such as getChildAt(index) and getChildByName, etc, which I believe should return a reference or pointer value, since these methods are simply meant to expose a child to operations, not transfer ownership.
Finally, the issue and the reason for this question, is in the following situation. Lets assume we have two Sprite objects which are children of the root of display list, Stage. Let's say we have a third child Sprite.
Stage newStage;
std::unique_ptr<Sprite> parentOne(new Sprite);
std::unique_ptr<Sprite> parentTwo(new Sprite);
newStage.addChild(parentOne); //Stage takes ownership of parentOne
newStage.addChild(parentTwo); //Stage takes ownership of parentTwo
std::unique_ptr<Sprite> someChild(new Sprite);
parentOne->addChild(someChild) //parentOne takes ownership of someChild.
Now, somewhere else lets say in the code base of the game or whatever using this framework, someChild is accessed via getChildAt(int index);.
Sprite& child = parentOne->getChildAt(0);
It would be perfectly legal for the following to then happen.
parentTwo->addChild(child);
The addChild method handles removing the child from it's previous parent, if a parent exists, so that the new parent can now make this child part of its section of the display list.
I'm returning the child(ren) from each sprite as a reference or pointer, because we don't want to hand off ownership (in methods such as getChildAt()), just provide access to the child. We don't want to hand it off as a unique_ptr and have it fall out of scope and die.
However, as I say, it would be perfectly legal and normal for this child (now accessed by a reference or pointer) to be passed off to another container (lets say in a drag and drop operation, dragging an item from one list to another). The problem we have now is that the unique ownership needs to be transferred from one parent to another, but we only have a reference or raw pointer.
I'm wondering what a sane solution to this problem would be. If I return a pointer, is it possible to transfer the ownership correctly at this stage?
void Sprite::addChild(Sprite* newChildToOwn)
{
/* by checking newChildToOwn->parent we can see that the child is already owned
by someone else. We need to not only remove the child from that parents' part of the
display list and add it here, but transfer exclusive object ownership of newChildToOwn
to this->.
*/
}
The release method gets you the pointer to the object and releases it from the unique_ptr
http://en.cppreference.com/w/cpp/memory/unique_ptr/release
For your structure, you should probably have method called releaseChild(index) that handles you the ownership by returning pointer.
To transfer ownership you need to have access to the unique_ptr as the raw pointer knows nothing of how it is being used.
Would it work to have the remove child method return the unique_ptr so that the object is kept alive during the transfer and the Sprite will be able to take the ownership? This will allow references to be used in other places as you have already.
I wrote a simplistic DBResourceMonitor class which is used by a set of database classes. When an instance of one of my database classes is created, it registers itself, and when destroyed, it unregisters itself with a singleton instance of DBResourceMonitor. When the application terminates, that global instance of DBResrouceMonitor is destroyed, which checks to make sure that there are no remaining registered instances of any of the classes that it monitors (i.e. that for every register, a unregister was called), and issues a TRACE output and ASSERT if there was a mismatch.
This is all well and good... until I put a couple of these database objects as members of my global application object. Hence, both the global application object, and the DBResourceMonitor are global singletons, and the application is the first to be constructed, hence the last to be destroyed, and hence when DBResrouceMonitor is destroyed, the members of the app object have yet to be unregistered, and so it throws an error indicating that there were mismatched register/unregister calls.
As far as I am aware, there is no way to ensure that the DBResrouceMonitor is constructed before the application object (and therefore destroyed afterwards).
Is this correct? Is there a clever way around that, or a way to rethink the above so that I can still track whether everything was taken care of before the final thread terminates?
Instead of having the objects register/deregister themselves with a singleton, you need to store the references to those objects in a collection property of the Singleton. So instead of doing:
var x = new MyDBObject();
you would use a factory pattern like:
var x = DBResourceMonitor.GetDBObject();
and somewhere in DBResourceMonitor you could manage a collection of MyDBObjects
MyDBObject GetDBObject()
{
//construct and save a MyDBObject or retrieve one from a list.
}
You could let the database object be the same as the resource monitor, by having a base class that "registers" the database object in its constructor, and "deregister" it in the (virtual) destructor. This way you can just create the object and not worry about singletons or extra monitor classes. The collection of objects would of course be a private static member in this base class, possibly protected in case of you using multi-threading.
I would also use std::unique_ptr instead of raw pointers, or possibly std::shared_ptr.