Hi. I'm Jesper Pedersen from
KDAB. We're talking about how we integrate the C++ layer with the
QML level. There is one thing that is worse than getting your teeth pulled out and that is pointers
that you leak. So, we want to avoid that at any cost. Which pointers do we talk about in this
setup, here? We talk about the QObject pointers that are either owned on the C++ side,
using, say, the parent/child relationship or your explicitly calling delete on them. Or they are
owned on the QML side where we have the garbage collector. So, who owns those? We do not want them to
be deleted twice, but, on the other hand, we do not want them to be deleted zero times, either. There is
this in-between that is the magic soft spot. The rule is as follows: elements that
have been created on the C++ side are owned by the C++ side. So far, we've only seen how
we can create objects on the C++ side. So, for your own object, we haven't seen that yet how you can
create those on the QML side. We'll see that in the next two videos. Elements that have been created on
the QML side, on the other hand, are owned by QML. You can specify that using setObjectOwnership,
where you specify which side they belong to. Now, there's one exception and that's the whole
reason why we have this particular video here. Had it just been the general rule, everything would
be defined. But there's one exception -- namely, if you export a QObject that is parentless from
a Q_INVOKABLE method, then it will actually be owned by the QML side. And I have an example that
shows you how terrible things can go. So, let's just jump right into it. Let's just run the example
right away. Let's go to the QML file, to start with, and see what we
do here. I got a column, and the column has a repeater to fill it. The repeater fills mouse
area.press. So, if the mouse is being pressed down, the model is zero elements. Otherwise,
it's _userList.count. And _userList is an object that I exported from
the C++ side. The elements that we see in that list, over here, are simple
rectangles that have a text inside. And the text looks like this: text: _userList.userAt
(model.index).name. So, on my C++ side, I have a poor man's version
of a model. It can tell you how many elements there are -- that is what my userList.count tells me --
and you can go and ask for each of those elements using this userList.userAt
index. Now, I press down on my mouse button and that means that the mouseArea.pressed
is now true, meaning that I'll have zero elements. But when I release the mouse
button, my application goes away. I can look at my application output. It says the
process was ended forcefully and the program has unexpectedly finished. Well, it's a matter of
who's looking at it. I expected it to finish. I used that joke already, didn't I? Oh, man. I'm
bad. Let's go and look at the C++ side of how we are exporting our objects and what we're
doing with them. So, on the C++ side, I have this _userList that I export, and my userList
looks like this: it has this property that is called count. That's the one I use there, and it
has this Q_INVOKABLE that returns a QObject pointer. Obviously, because that's what we
are trying to get in trouble with -- the QObject pointer userAt and then a given element. It has a
vector of user pointers that are the elements that I export to the QML side. So, my constructor...
simply setting up my four users, here. A user is a very simple subclass of QObject. It has
this property called name. That's what I read on the QML side. And, well, that's basically it. Observe
that my user does not specify a parent, here. And as my user's constructor doesn't do
anything special with parent either, here, I simply have a QObject without any parents
and that's the key thing about this example, here. So, I have my user; it's a QObject
that doesn't have a parent. I return it in this method called userAt. So, I return the
element here -- return m_ userAt index. And remember the rules. Elements created on
the C++ side will have C++ ownership. Elements created on the QML side will
have QML ownership, unless it's a QObject subclass that is
returned from C++ via a Q_INVOKABLE -- which is exactly what we do. In that case, it will
have JavaScript ownership. So, when I press down the mouse button, my model will now be zero, which
means that all my elements in that model will go away. The JavaScript interpreter will say that
they are out and they are not used anymore and then it will call the garbage collector to go and
kill them. And then, when I release, I again say that my list is four elements long, because my
list didn't change. It was just the four users that now have been deleted in the list and, therefore,
are dangling pointers which have this tendency of making your application crash. And we
can see here that, on my QML side, whenever I press down my mouse button, not only
does this mouseArea.pressed rest
and my model is updated to be zero, I also call
the garbage collector. So, garbage collect, please unpress -- do garbage collector right away so that we
can get those elements deleted and force that crash through. The cure is even commented out, here -- simply
said that the objects should have C++ ownership. And now, when they have C++ ownership,
they will no longer be deleted by the QML side. Of course, QML will notice they go out of scope.
But, yes, they are owned by the C++ side. Of course, that's one cure. The other cure would
be to simply give them a parent on the C++ side, because, as it stands now, they do not have a
parent. So, I still need to be careful that it is I who needs to delete
them, whenever they go out of scope. I can feel that you don't trust me. So, let me
just run the application, again. You can see. Press, they are away. They're here. They're away. They
are here. They're away. They are here. Thank you for not trusting me. But, you see, it does actually work.
That was just a small intermediate. In the next video, we're going to see how to create new elements that we can
instantiate on the QML side. And those, especially those, elements will have QML
ownership. So, stay tuned and, until then... Did I mention please do subscribe
to our channel? And, have a great day.