[Development] Qt 5 types under consideration for deprecation / removal in Qt 6
giuseppe.dangelo at kdab.com
Wed May 29 15:33:23 CEST 2019
Il 29/05/19 12:53, Mutz, Marc via Development ha scritto:
> 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.
I'm assuming that they were made public to help users build their own
CoW types. In that regard, deprecating/removing them would leave users
in the cold (without a public replacement).
So either the proposal is to make the new one public as well, or I don't
see an easy way out of this.
> == Java-style iteration
> (https://codereview.qt-project.org/c/qt/qtbase/+/262344) ==
> 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.
I don't think that it.remove() can be a motivation -- after all it's
just as easy to produce quadratic behavior with it = vector.erase(it).
The real motivation should go along the lines of "is having them worth
it"? Do they make life any easier in Modern C++? Do we still "target"
> == 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
The only missing bits would be the QScopedPointer deleter companion
classes. Probably the only missing one is the "delete later" one, that
would benefit from being renamed anyhow (one can use such a deleter in
other smart pointers). The other ones can be refactored via search and
replace -- e.g. QScopedPointerArrayDeleter<T> =>
std::default_delete<T> or something like that.
> == 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
> std::hash<> implementations.
> Actual problem?
A problem to provide string/byte hashing and a hash combiner (for
private use)? I don't think so.
But I'm not sure I understood the proposal: is it in practice suggesting
to rewrite all qHash overloads for builtin/Qt types to forward to
std::hash? (Basically just move the implementation and who-calls-whom)
> == 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.
This would be a lovely experiment to try. Apart from QPainter, how many
other classes work in terms of a QPaintDevice*?
> == QRegExp ==
> Is QRegularExpression good enough these days? :)
I think that thanks to Samuel Gaist it's also got wildcard matching. The
only concerns are
1) the bigger footprint in general; that gives an argument for creating
a build stripped of QRegularExpression, which in turn would break many
low-level APIs (QDirIterator, for example)
2) should QRegExp stay in bootstrap? I have no idea of what's happening
regarding to that in Qt 6.
> === QAtomic -> std::atomic ===
> It already is just a thin wrapper around std::atomic, so there's not
> much point keeping it.
We're very lucky as the std atomics use even the same names that
QAtomics are. There are probably a minor of points where tooling will
help at porting, e.g. plain load/store having strictier semantics in
std::atomics (seq_cst in std::, relaxed in Qt). (What I mean is that
they're safe to port away, but the correct port would be towards a
> === 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.
There are a few practical problems:
1) std::mutex is not constexpr+noexcept everywhere
2) std::mutex is still not futex-based everywhere => it's still
significantly slower than QMutex
These block the upgrade path, at least for now.
> === 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.
Does it actually do it better, though? For instance, is
std::condition_variable still backed by a pthread_cond_t? That means a
wait() on it is a POSIX cancellation point, which gives you extra costs.
MIA: QSemaphore, for which there's nothing yet in the stdlib (maybe in
20, pending P1135).
> = 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).
While QStack can simply be deprecated in 6.0 and basically just stay
around as-is, QQueue inheriting from QList is much more problematic if
QList becomes QVector and loses the prepend optimization.
> == 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
There's an extra feature that needs to be ported before deprecation is
possible, namely the support for casting QVariants holding
QSharedPointer<QObject> and similar plumbing. I've added
qobject_pointer_cast in 5.14, and magic QObject handling has been
deprecated since 5.0 already.
> = 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.
I don't think this is realistically possible. What I would suggest, to
bring the maintenance burden down to a minimum, and increase our
compatibility with stdlib to a maximum, is have QHash/QMap to be a CoW
wrapper for std::(unordered_)map . The inner data structure should be
exposed to the user, allowing for deep integration between stdlib and Qt.
> == 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.
QHash has the same problem with QMultiHash. And the consideration is
just as above. For wrapping solution to be 100% API compatible with Qt 5
QHash/QMap, it will therefore require:
1) (minor) deprecate insertMulti => solution, use a QMulti* container
and plain insert
2) (minor) deprecate bidirectional iterators on QHash =>
std::unordered_map only has forward
3) (major) QMultiMap and std::multimap insert equivalent keys in
opposite order. Breaking this behavior is another deep paper cut à la
Thanks for starting this discussion,
Giuseppe D'Angelo | giuseppe.dangelo at kdab.com | Senior Software Engineer
KDAB (France) S.A.S., a KDAB Group company
Tel. France +33 (0)4 90 84 08 53, http://www.kdab.com
KDAB - The Qt, C++ and OpenGL Experts
-------------- next part --------------
A non-text attachment was scrubbed...
Size: 4329 bytes
Desc: Firma crittografica S/MIME
More information about the Development