I have this code:
QVariant componentFromCode(QString code) {
QQmlComponent * component = new QQmlComponent(engine);
engine->setObjectOwnership(component, QQmlEngine::JavaScriptOwnership);
connect(component, &QQmlComponent::destroyed, this, &Factory::echo);
component->setData(code.toUtf8(), QUrl());
return QVariant::fromValue(component);
}
But Factory::echo()
is never called, which means the object gets leaked every time the function is called.
This is what I have on the QML side:
onClicked: {
var code =
'import QtQuick 2.3
Rectangle {
width: 50
height: 50
color: "blue"
}
'
stack.push(Factory.componentFromCode(code))
gc()
}
I explicitly set the object ownership, and explicitly call gc()
to force garbage collection, but the destroyed()
signal never gets emitted, therefore the object never gets deleted. From what I read this is supposed to happen automatically in QML.
Note that it works to:
var comp = Factory.componentFromCode(code)
stack.push(comp)
comp.destroy()
But it is just not convenient, I'd like to have the object destroyed automatically as it falls out of scope, or alternatively, remain alive for as long as it is referenced by QML code and be destroyed when it is no longer needed, something that might be hard/absurd to do manually in many situations.
EDIT: The stack example happened to be my actual code, but I guess it is not that good of an example, seeing how the stack taking ownership over the component is assumed. I don't get any lifetime management even in such simple cases as:
function JSfoo() {
var obj = CXTProp.getCppQObjectStar()
console.log(obj.objectName)
} // QObject is not collected here
or...
QtObject {
property QtObject: CXTProp.getCppQObjectStar()
} // QObject is not collected after the object is destroyed
I don't think the object is leaking. Try this out:
and in QML:
After
test()
the object isn't collected, and when you close the application, theecho()
slot is never triggered, but the debug statement from the destructor is indeed showing up in the console:If you call
gc()
in the scope of the function it doesn't work, probably because the object is still referenced in it:However, if you do it like that:
It works, because the garbage collection is triggered after the reference to the object has fallen out of scope:
It seems that when the application exists, it doesn't handle the
destroyed()
signal, so theecho()
slot is never triggered which is probably what misled you into believing the object is leaking unmanaged. I am not sure if this is a product of Qt's design or a bug. TheTest
object is instantiated on the stack inmain()
so it should definitely still be "alive" when objects, managed by QML are being destroyed, as should be the event loop it uses, so I would expect to seeecho()
before the application exits, but it seems this is not the case. But that's not the scope of the question, point of the matter is objects are managed and will be collected when they are no longer referenced and garbage collection is triggered.