[Development] The future of smart pointers in Qt API

Vitaly Fanaskov vitaly.fanaskov at qt.io
Mon Feb 3 14:59:05 CET 2020


If we're going for this logical fallacy, then let's up the ante: a unique pointer is just a shared pointer without copy semantics. Why not using shared pointers everywhere?
Well, I hope it was rhetorical question, please, let me know if not.

The difference between shared pointer and unique pointer is fundamental. But there is no fundamental difference between unique pointer and scoped pointer. The both uniquely own a resources and resource lifetime is equal to smart pointer lifetime unless it explicitly prolonged. The only difference is a way how you can do that. In case of scoped pointer you can invoke method "take", in case of unique pointer you can also use move semantic. Looks like that scoped pointer is just yet another redundant entity.

Introducing an alias should satisfy some people who used to use scoped pointer.

And an example where I cannot replace a unique pointer with a shared pointer without losing readability and maintainability?
A straw man? Please, stop.

Like this?

std::unique_ptr<Foo> ptr = ~~~;
return ptr;
For example. With a scoped pointer it's a bit harder to do that, but also possible, I think, for example:

QScopedPointer<Foo> ptr = ~~~;
return QScopedPointer<Foo>(ptr.take());

Which one would be the redundant one?
Obviously scoped pointer. I've described why.

What? This is absurdly false -- the Standard Library is part of the C++ standard itself.
Which doesn't mean that this is a part of the programming language. If you read carefully some parts of the standard, you can notice that, for example smart pointers or containers are not mandatory. For example:

"This Clause describes components that C ++ programs may use to organize collections of information."

Just a recommendation or an assumption. But this is a rabbit hole. I don't want to argue here. This is not related to the main topic.

Please also see this from the eyes of someone else who comes from a general purpose C++ background, where usage lock() is established (for how much absurd that naming choice is); then gets the Qt equivalent, and wonders why it _hasn't_ got lock(), despite Qt having 0.something% of the C++ market share.
Yes, I see what you mean and I entirely agree. We should think how to have some compromise here.

And again see this the other around too: many C++ users get used to the C++/Boost/Abseil/... naming convention and may find Qt ones "unusual".
Possible. But we're discussing Qt and its ecosystem and we also have to care about Qt users.

Changing the interface in any way which are incompatible with the Standard counterparts is a _terrible_ idea. It kills the principle of least surprise; it makes such facilities incompatible with the STL counterparts, preventing interexchange of data and code; and come Qt (N+1), it will prevent a clean pass of s/QtFoo/std::foo/g over the codebase.
It's not a big issue if we have Qt wrappers around std smart pointers. A standard smart pointer that is under the hood should be easily accessible.

Regarding POLA, it works both ways. If you have Qtish something you usually don't expect that this is fully compatible with STL counterpart. Which is probably not good, but here we are. In case of Qt wrappers around smart pointers, having them at least easily convertible to std pointers is a good move.

This is wishful thinking, or, famous last words.

First: it costs in terms of development bandwidth that is NOT being used to improve the areas where Qt should shine; it's instead used for reinventing wheels.

Second: history proves this false. See for instance the story with Qt containers, which are *still* missing range insertion (C++98) (and some range construction), emplacement (C++11), support for move-only types (C++11), and so on. On what grounds should one believe that after 9 years suddenly Qt will catch up with the development of these building blocks?
Well, yes, I tend to agree here. At least with the last paragraph for sure.

How do you integrate QSharedPointer with std::shared_ptr exactly?
If QSharedPointer is just a wrapper around std::shared_pointer it should be easy. Adding one more constructor and an operator to the wrapper.

On 2/2/20 12:12 AM, Giuseppe D'Angelo wrote:
Hi,

Il 01/02/20 22:55, Vitaly Fanaskov ha scritto:
   The consensus was reached against such a decision. A scoped pointer
   should not be able to escape scope. Yes, in C++17 this is now not
   entirely true, but the name strongly implies it.

Perhaps, it's a good time to reconsider it. Scoped pointer is redundant entity in light of modern C++. It's just an unique pointer without move semantic.

If we're going for this logical fallacy, then let's up the ante: a unique pointer is just a shared pointer without copy semantics. Why not using shared pointers everywhere?


Please, give me at least one example when I cannot replace scoped pointer with unique pointer without losing readability and maintainability.

And an example where I cannot replace a unique pointer with a shared pointer without losing readability and maintainability?


Unique pointer could "escape a scope" only explicitly.

Like this?

std::unique_ptr<Foo> ptr = ~~~;
return ptr;



So I'm still not convinced that we need to have one more redundant entity.

Which one would be the redundant one?


We have more than enough. This is possible to introduce an alias just to keep naming convention people get used to, I guess, but I'm not sure if this is really required.

About QUniquePointer: what's the point of reinventing std::unique_ptr
under a different name?

So, first of all, not reinventing. I'd say adopting. The main question I see through some your posts in this thread is "why do we need Qtish wrappers at all?". Correct me if I'm mistaken, please.

That's the question indeed. What's the tangible net benefit of having a Qt wrapper?


Until that I'll answer this question __
There are a few pros of having Qt wrappers around std smart pointers. To make it clear, saying "Qt wrapper" I mean a class that contains std smart pointer as a field and has more Qtish interface. Not inherits a std smart pointer.

And I've asked: how this Qtish interface for std::unique_ptr be different exactly?


Pros I can see:
1) Qt style
STL has different naming convention that looks alien to Qt API. It leads to inconsistency. STL is not a part of C++ language itself and cannot be considered as a default standard.

What? This is absurdly false -- the Standard Library is part of the C++ standard itself.


The fact that some people might get used to some names doesn't mean that these names are good in terms of self-explanatory.  > For example, how do I understand without documentation what does
"weak_ptr::lock" do? Something like "asStrongRef" is easily understandable just by reading code.

With this I can totally agree. As I said countless times, the only way to influence such naming decisions is working _with_ upstream (by the way, the meetings are pretty much public) and bringing your arguments on naming there. After, it's too late, and as an overall minority in C++ we'll get those decisions made by someone else and we'll just have to live with them. It's not a good position to be in.

Between C++11, 14, 17 and 20, by heart I can only name _one_ thing that has been introduced in the Standard Library which has had an inspiration coming from Qt (C++20's std::map::contains()).


Please also see this from the eyes of someone else who comes from a general purpose C++ background, where usage lock() is established (for how much absurd that naming choice is); then gets the Qt equivalent, and wonders why it _hasn't_ got lock(), despite Qt having 0.something% of the C++ market share.

(I know QWeakPointer has got lock() now.)


I'm not 100% sure who is responsible for naming STL classes and methods, but this person(s) did really good job in terms of reducing symbols count. I'm just wondering why not "w_p::l" instead of "weak_ptr::lock", it looks much shorter!  In my opinion, we shouldn't sacrifice readability to reduce symbols count.

The "who" is a lot of people.

https://isocpp.org/std/the-committee



After all, many Qt users get used to Qt naming convention and style.

And again see this the other around too: many C++ users get used to the C++/Boost/Abseil/... naming convention and may find Qt ones "unusual".



2) Flexibility
It will be much easier to extend or reduce interface if we need it. Changing implementation is also will be easier if someone needs to have a different smart pointers under the hood on some platforms.

Changing the interface in any way which are incompatible with the Standard counterparts is a _terrible_ idea. It kills the principle of least surprise; it makes such facilities incompatible with the STL counterparts, preventing interexchange of data and code; and come Qt (N+1), it will prevent a clean pass of s/QtFoo/std::foo/g over the codebase.



3) Low maintenance costs
We just need to replicate an API at first implementation. After that, introducing new methods that might occur in an upcoming standards should be easy enough.

This is wishful thinking, or, famous last words.

First: it costs in terms of development bandwidth that is NOT being used to improve the areas where Qt should shine; it's instead used for reinventing wheels.

Second: history proves this false. See for instance the story with Qt containers, which are *still* missing range insertion (C++98) (and some range construction), emplacement (C++11), support for move-only types (C++11), and so on. On what grounds should one believe that after 9 years suddenly Qt will catch up with the development of these building blocks?


4) Easy to integrate with std smart pointers
A few constructors/operators/methods could solve this problem. It means that it should be possible to integrate with a code written with using std pointers.

How do you integrate QSharedPointer with std::shared_ptr exactly?



Finishing this, I'd like to say that having consistent APIs that don't violate principle of less astonishment is important thing. That's the main reason why personally I vote for the option with Qt wrappers.

If I were a developer coming from standard C++ to Qt, the principle would apply in that direction too: why in the world Qt felt the need to reinvent all my vocabulary types?

My 2 c,

--
Best Regards,

Fanaskov Vitaly
Senior Software Engineer

The Qt Company / Qt Quick and Widgets Team
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/development/attachments/20200203/2f9c48c4/attachment-0001.html>


More information about the Development mailing list