[Interest] Qt ownership model

charleyb123 . charleyb123 at gmail.com
Sat Jun 4 17:09:39 CEST 2016


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).
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.
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/interest/attachments/20160604/051c7ebf/attachment.html>


More information about the Interest mailing list