[Interest] Qt ownership model
Konstantin Tokarev
annulen at yandex.ru
Sat Jun 4 17:48:23 CEST 2016
04.06.2016, 18:10, "charleyb123 ." <charleyb123 at gmail.com>:
> I won't be active in this thread, because IMHO this is the stuff of legends: We are about to usher in a new decade of flame wars for all of C++ with this topic (and these wars are underway in other C++ communities outside Qt).
>
> However, I want to chime-in here for Qt, and then I'll not be active on this thread (but I will lurk).
>
> C++ is a value-semantics stack-based language, where heap allocations demand that the developer (and the system design) manage object lifecycle. This is different from reference-based languages like C# or Java that have garbage collection.
>
> This means that in C++, the act of "Design", or even the act of "Software Development" is:
>
> (1) Decide what objects exist (e.g., types-and-instances)
> (2) Decide who owns them (e.g., object-lifecycle)
>
> There is no (3).
>
> Yes, the following idiom is currently being marketed to the C++ community:
>
> auto f = std::make_shared<Foo>(...);
>
> This is to free the developer from considering implications of (2).
I disagree, (2) is still present as the choice of make-function. It's up to you to decide if it will be Foo(...), std::make_shared<Foo>(...), std::make_unique<Foo>(...), or something else.
> However, there are real-world consequences.
>
> This is a highly precarious design pattern at scale. This is the new "goto". Without sufficient discipline within the design to explicitly manage lifecycles, this is the equivalent of a "global" instance of unknown duration and unknown mutation across threads, arbitrarily, without any controls.
>
> It is a very dangerous design decision. Who else is accessing the object behind your shared pointer? Are they all properly participating in the link count? Is another thread modifying the object while you are reading? Are you sure? How will you debug when you find out you were wrong?
>
> Qt's historic model is parent-ownership, and if no parent, then the developer explicitly manages ownership with "QObject::deleteLater()". There are other patterns, and indeed within Qt, you are encouraged to use these mechanisms within your higher-order patterns. For example, you are free to put your "custom-deleter" within your "std::shared_ptr<>" or "std::unique_ptr<>".
>
> However, injecting "std::shared_ptr<>" and "std::unique_ptr<>" ubiquitously through an API and library will go down in history as one of the biggest design mistakes in C++, precisely because attention to (2) above should be more explicit within the system design. IMHO, a C++ developer cannot be forgiven inattention to that detail.
>
> If you want to scale, the C++ developer must do both (1) and (2).
>
> I concede that for small projects, scaling is not an issue. Yet.
>
> --charley
>
> On Sat, Jun 4, 2016 at 7:14 AM, Nye <kshegunov at gmail.com> wrote:
>> Hello,
>> Since this is opinion based I will give my opinion without explicitly stating it's just a personal view on the subject on every line.
>>
>> On Sat, Jun 4, 2016 at 3:55 PM, Антон Жилин <antonyzhilin at gmail.com> wrote:
>>> A trend in modern C++ is AAA idiom.
>>
>> The newest and hottest fad, which I consider to be a complete and utter *rap.
>>
>>> The idea here is to *prohibit* new in user code, because ownership semantics of raw pointer is undefined.
>>
>> That's a matter of some debate. I consider the ownership to be passed to the person invoking new, unless otherwise stated (e.g. in Qt's documentation the ownership transfer(s) are duly noted).
>>
>>> How can we apply these idioms to Qt?
>>
>> The question rather is: Should we?
>>
>>> Yes, if we add a couple of helper functions!
>>>
>>> 1. Non-widgets can usually be constructed on stack or using std::unique_ptr -- Great
>>
>> Applies to widgets as well. A stack allocation is much faster and robust than new-ing needlessly. So if you don't need to keep binary compatibility (e.g. when you have widgets in an application, or not directly exposed from a library) I'd always opt for stack allocation. No need to have two heap allocations, when I can get only one (the d-ptr of the QObject).
>>
>>> 2. If we construct an object with a parent, we do something like this:
>>> auto pushButton = new QPushButton(..., parent);
>>> -- Not so great, we need to look at parent to know if we need to delete pushButton
>>
>> There was recently a thread on this same mailing list dealing with similar issues. For most intents and purposes you can delete the child directly, if that's not possible the deletion can be scheduled through the event loop. I for one don't see any reason to complicate matters.
>>
>>> 3. Widgets without a parent are usually used with QSharedPointer
>>
>> "Usually"? Not in my experience. Widgets without a parent I just create in the stack if possible. If not, I either use QScopedPointer when I own them, or QPointer when ownership is transferred to Qt. I don't intend to share my widgets, much less pass them across threads, so I don't see any good reason why I would want to use a _shared_ pointer to keep reference to them
>>
>>> What do you think?
>>
>> Well that's pretty much what I think. You can agree or disagree, but I really don't see any reason to embark in writing AAA-style.
>>
>> Kind regards,
>> Konstantin.
> ,
>
> _______________________________________________
> Interest mailing list
> Interest at qt-project.org
> http://lists.qt-project.org/mailman/listinfo/interest
--
Regards,
Konstantin
More information about the Interest
mailing list