[Development] The future of smart pointers in Qt API

Daniel Teske qt at squorn.de
Tue Feb 4 21:03:08 CET 2020


Am 04.02.2020 um 17:47 schrieb Volker Hilsheimer:
>> On 4 Feb 2020, at 16:12, Ville Voutilainen <ville.voutilainen at gmail.com> wrote:
>>
>> On Tue, 4 Feb 2020 at 15:40, Volker Hilsheimer <volker.hilsheimer at qt.io> wrote:
>>>>> This works, but now you are encoding the visual hierarchy of the widgets in two places: when asking the presumed parent to create the widgets; and when setting up the layout, which might do things differently (esp once you start refactoring complex UIs).#
>>>> That's not a problem. The code simply behaves as if you would have used the current constructors that take a parent parameter.
>>>>
>>>> Ownership transfers between different qt parents don't violate the invariant. And they continue to work just like before.
>>>
>>> So how is the above usage of makeChild an improvement over calling operator new to instantiate your objects?
>>
It's also clearer to see the parent child relationship.

And it switches what the easiest way to construct a object is. Currently 
it's less code to create a object without a parent, whereas with my 
patch and the deprecation enabled the easiest way to handle qt objects 
is via makeChild.

>>
>>>> But that just means that QBoxLayout::addWidget(std::unique_ptr<>) has to behave imho saner in that edge case and actually delete the widgets that were added but never parented. (And I should really implement that to show how it would work.)
>>>
>>> That seems like a terrible idea. One of the layout’s jobs is to set up the parent/child hierarchy so that you as a developer don’t have to.
>> I don't see how that idea changes that.
>
> Iif the layout deletes widgets that were created without parent, instead of adding it to the correct parent, then that’s a change. You have to create widgets with parents, and add them to the layout (which might then add it to another parent, which at the very least introduces unnecessary overhead of ChildAdded/Removed event processing).

I didn't explain the behaviour well enough, so sorry for the confussion.

The layout takes care of the child widgets only if it never parented the 
widgets.

If the layout parented the widgets, either in setLayout or because the 
layout already had a parent, then those widgets are owned by the parent 
widget not by the layout. Or because the layout was added to a different 
layout that has a parent.

Essentially, if in the layout dtor the widgets don't have a parent, then 
those widgets are owned by the layout.

And I'm open to only do that for those widgets that were explicitly 
moved into the layout, though I have a slight preference to changing the 
existing behaviour.


>
>>> Do we really want to make it harder for people to write UIs just because the resulting code doesn’t satisfy a C++ idiom?
>> It's not a question of satisfying idioms for the sake of satisfying
>> idioms, it's a question of avoiding bugs that we know
>> based on decades of experience to be difficult to avoid with raw pointers.
>
> That’s my point:
>
> I do not believe that the decades of experience we have with QObject’s parent/child model support the claim that it is inferior to using smart-pointers. It’s not something people constantly struggle with.

The problem is that you have to actually know what every method does, 
which isn't always obvious and is not always documented.


>
> That doesn’t invalidate the suggestion that we should use smart pointers in Qt code, or in Qt APIs where we are not benefitting from QObject trees.
>
>
>>> If you don’t care about the things that QObject/QWidget does for you, then don’t use QObject/QWidget. And if you do use QObject/QWidget and get a consistent object model from it, then I’m really not convinced that adding smart pointers to the API is making the code clearer, or in any way more explicit. It’s not like the ability of using std::unique_ptr means that people no longer have to be familiar with Qt’s basic concepts to use it correctly.
>> Correct, but if code moves a std::unique_ptr into a function call
>> argument, I know that ownership is transferred, by just glancing at
>> the code. With a raw pointer, I don't know that.
>
> But ownership isn’t transferred if you call QLayout::addWidget; it is never transferred to the layout object - it might be transferred to the QWidget that the layout operates on.

Well, that's a matter of perspective. With the API I outlined, ownership 
is indeed transferred to the layout, which then either a) immediately 
transfers it to the widget, b) transfers it later on e.g. setLayout, c) 
if neither happens the layout owns the widgets.

Now, it's worth reiterating that this is a edge case. This is only about 
layouts that never ever get added to a widget hierarchy. That should be 
rare.

daniel


More information about the Development mailing list