Introduction to Qt/QML (Part 48) - QObject Ownership

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
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.
Info
Channel: KDAB
Views: 1,790
Rating: undefined out of 5
Keywords: QML, C++, Qt, KDAB
Id: wQ83g0CK1U0
Channel Id: undefined
Length: 8min 25sec (505 seconds)
Published: Wed Jan 27 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.