1

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.

Community
  • 1
  • 1
Matthew Kraus
  • 6,660
  • 5
  • 24
  • 31
  • At a very quick glance through the code, it looks like the root context. But better not leave object lifetime management to chance https://bugreports.qt.io/browse/QTBUG-50319 – dtech May 05 '17 at 19:13

2 Answers2

2

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.

m7913d
  • 10,244
  • 7
  • 28
  • 56
  • Your reasoning makes sense. I needed to post a follow-up question because my situation is a bit more complicated, but this explains my original question well. Follow up question is here: http://stackoverflow.com/questions/43864080/safely-deleting-qml-component-being-used-in-stackview-transition – Matthew Kraus May 09 '17 at 07:56
  • According to the documentation, the visual parent is set by QQmlQuickItem::setParentItem: http://doc.qt.io/qt-5/qquickitem.html#parent-prop. I think your comment about "transfer the ownership to the visual parent using `QObject::setParent`" might need to be edited. It is my understanding that `QObject::setParent` does not set the visual parent of a QML item. – Matthew Kraus May 09 '17 at 18:37
  • @MatthewKraus You are completely right. Is my updated version better? – m7913d May 09 '17 at 18:43
  • thanks for the update. In general I think this approach is a good one. – Matthew Kraus May 09 '17 at 20:10
2

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;
}
Joshua D. Boyd
  • 4,808
  • 3
  • 29
  • 44
  • I do not completely agree on your experimental method to check the parent of `object`. The child-parent relationship is only one (common) way to manage the ownership in Qt. As pointed out in your code snippet, clear _does_ take the ownership of the object as long as it is `Loading`, but it is _not_ its parent. – m7913d May 06 '17 at 09:05
  • Ok, so I need to delete the object. But what if QML is still using it? Would you mind looking at my follow-up question: http://stackoverflow.com/questions/43864080/safely-deleting-qml-component-being-used-in-stackview-transition – Matthew Kraus May 09 '17 at 07:54
  • [`QQuickItem::setParentItem`](http://doc.qt.io/qt-5/qquickitem.html#parent-prop) will not transfer the ownership to the _visual_ parent item. You should use [`QObject::setParent`](http://doc.qt.io/qt-5/qobject.html#setParent) instead. See [Concepts - Visual Parent in Qt Quick](http://doc.qt.io/qt-5/qtquick-visualcanvas-visualparent.html) for more information. – m7913d May 09 '17 at 09:26