[Development] Qt 5 types under consideration for deprecation / removal in Qt 6
marc at kdab.com
Wed May 29 12:53:35 CEST 2019
Here's a list of stuff I consider has served it's purpose and is no
longer needed, with respective replacements:
= Priority 1 =
== QSharedDataPointer / QExplicitlySharedDataPointer ==
These are basically Qt-internals, and should never have been public in
the first place. It's _because_ they are public that we have two of
them, and soon a third one (properly non-public):
https://codereview.qt-project.org/c/qt/qtbase/+/115213 That commit's
message also explains what's wrong with the QSDP and QESDP.
== Q_FOREACH -> ranged for loops
Q_FOREACH is less readable (because it allows mutating the container
under iteration), and produces _a lot_ of code. It also is intrinsically
tied to just a few Qt containers (excluding QVLA). Ranged for loops work
on anything, incl. a C array. Also, as a macro, it will continue to
cause problems down the road (e.g. with modules). Being a macro also
means that it cannot deal with value_types that contain a comma.
=== related: Q_FOREVER -> for(;;) ===
Suggested by Lars in ibid. Basically because it's a macro.
== Java-style iteration
It's very easy to write quadratic loops with it.remove(), and a review
of Qt code has shown that some users still use container.remove(), which
is just as unsafe as with STL iterators. I also noted between 100b/loop
and 5KiB for four loops of text size savings.
== QScopedPointer -> std::unique_ptr ==
Suggested by Thiago on
I agree. We now have std::unique_ptr, and it's movable. QScopedPointer
had the problem that it didn't know what it wanted to be:
boost::scoped_ptr or std::unique_ptr. A real scoped pointer would not
offer release(), a unique_ptr would need to provide move semantics.
QScopedPointer has release(), but no moves (were proposed, but not
== QLinkedList -> std::list
Of the Qt containers, this one is the most-unused (in Qt code), as well
as the one that's furthest behind it's STL counter-part. Whenever I use
std::list, I use it for splice(), a function that just cannot be added
to a CoW container. Qt is already almost completely QLinkedList-free.
Let's bury QLinkedList.
== qHash() -> std::hash ==
Suggested by Lars in
https://codereview.qt-project.org/c/qt/qtbase/+/261819. To be precise,
he's suggesting to specialise std::hash and have qHash() call std::hash.
Only problem I see so far is that std doesn't provide us with a tool to
hash composites. E.g. there's no std::hash for std::tuple (which would
mean we can std::tie the members and hash the result), and only C++17
adds some kind of raw bits hashing (via std::string_view). We'd need to
provide these building blocks ourselves, which can be done, but it means
we'll have at least _some_ qHash()-like functions we need for
== QPaintDevice ==
I'd like this to become a static interface. In very shortened terms:
everything that has a QPaintEngine *paintEngine() method is a paint
device. QPainter's ctor would become a template and do the virtual
dispatch internally, just like Sean Parent's document type in C++
This would solve a lot of problems: QWidget would no longer need to use
multiple inheritance, and QImage and QPixmap would become proper value
types, without virtual functions that create problems with move
semantics and swapping.
== QRegExp ==
Is QRegularExpression good enough these days? :)
== MT plumbing ==
Let's make use of the std facilities to enable checkers such as TSAN to
work without hacks. It's not Qt's business to reimplement threading
Probably need to keep some stuff around, like QThread, because of the
interaction with event processing, but before we add a lot of time
making the following classes play nice with the std, let's perspectively
=== QAtomic -> std::atomic ===
It already is just a thin wrapper around std::atomic, so there's not
much point keeping it.
=== QMutex / QReadWriteLock -> std::*mutex* ===
It has too many responsibilities. Where the std knows many different
mutex classes, Qt folds everything into just two.
We probably need to keep QRWL around a while longer, since C++ added
shared_mutex only in C++17.
=== QMutexLocker -> std::unique_lock ===
1:1 replacement in the vast majority of cases. unique_lock has a lot
more features (movable, adopting a locked mutex, not tied to any
particular mutex class, ...)
=== QWaitCondition -> std::condition_variable(_any) ===
Plumbing that std::condition_variable can do better.
= Priority 2 =
== QQueue / QStack -> std::queue, std::stack ==
These classes publicly inherit QList and QVector, resp., and are both
very inflexible (due to the fixed underlying container), as well as too
flexible (they offer non-queue, non-stack behaviour, such as iteration).
For QQueue, we have the additional problem that QList is going to be
deprecated/removed in Qt 6 (see previous discussion).
== QSharedPointer / QWeakPointer -> std::shared_ptr/weak_ptr ==
Once they are stripped of their magic QObject handling and QObject
handling returned to QPointer proper, they don't do much other than
std::shared_ptr, except being less flexible and largely untested for
= Priority 3 =
== QSet / QHash -> std::unordered_set/map ==
I'd really like to see these gone. Mainly to free up their names for OA
hash containers, something that the STL doesn't, yet, have.
== QMap -> std::map ==
These classes have taken some design decisions that make them very badly
integrated into modern C++. One is that QMultiMap is-a QMap. The first
and foremost is, though, that *it returns value_type, making ranged-for
useless for maps. If we're going to change the return value of *it,
though, we might as well kick the whole class out, too, since the code
adjustments on the user's parts would be roughly the same.
... to be continued.
Flame away :)
More information about the Development