From bb23a05905d7dc0e416a646e40592436daa939f2 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Thu, 28 Sep 2023 15:52:06 +0200 Subject: [PATCH] QWeakPointer: deprecate its relational operators They're fundamentally broken and should never ever be used. * op==(weak, weak) is heterogeneous, but at the same time it's unconstrained (!), may trigger UB (!) by doing a static_cast to a type which isn't the actual type of the pointee, and may outright crash (!) if the pointee has been deleted and there's virtual inheritance. * op==(weak, strong) compares the control blocks, i.e. does "owner_equal" comparison, not pointer comparison. Now QSP doesn't have support for aliasing, so the pointers stored by the smart pointers themselves always point at the owner object. Yet: given a QSharedPointer that is the last owning pointer to T and a QWeakPointer that tracks it, if one resets the shared pointer, then op==(wp, sp) will yield false (wp still points to the control block, sp does not), but op==(wp.lock(), sp) will yield true (both shared pointers are null). That doesn't make any sense. I'm leaving op==(wp, std::nullptr_t) in as a shorthand to check if the weak pointer is expired, but might deprecate that as well in a future commit. [ChangeLog][QtCore][QWeakPointer] The (in)equality operators of QWeakPointer have been deprecated. Always upgrade a QWeakPointer to a QSharedPointer (for instance, via lock()) before doing a comparison. Change-Id: Ia2f5f5e9e5558e1558b6084542532515c80b78b0 Reviewed-by: Thiago Macieira --- src/corelib/tools/qsharedpointer_impl.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/corelib/tools/qsharedpointer_impl.h b/src/corelib/tools/qsharedpointer_impl.h index 5dfc4614f9..1da9a48b60 100644 --- a/src/corelib/tools/qsharedpointer_impl.h +++ b/src/corelib/tools/qsharedpointer_impl.h @@ -652,28 +652,36 @@ public: // std::weak_ptr compatibility: [[nodiscard]] QSharedPointer lock() const { return toStrongRef(); } +#if QT_DEPRECATED_SINCE(6, 7) template + QT_DEPRECATED_VERSION_X_6_7("Comparison of QWeakPointers is inconsistent and may lead to crashes. lock() them and then compare the resulting QSharedPointers.") bool operator==(const QWeakPointer &o) const noexcept { return d == o.d && value == static_cast(o.value); } template + QT_DEPRECATED_VERSION_X_6_7("Comparison of QWeakPointers is inconsistent and may lead to crashes. lock() them and then compare the resulting QSharedPointers.") bool operator!=(const QWeakPointer &o) const noexcept { return !(*this == o); } template + QT_DEPRECATED_VERSION_X_6_7("Comparison of QWeakPointers is inconsistent and may lead to crashes. lock() them and then compare the resulting QSharedPointers.") bool operator==(const QSharedPointer &o) const noexcept { return d == o.d; } template + QT_DEPRECATED_VERSION_X_6_7("Comparison of QWeakPointers is inconsistent and may lead to crashes. lock() them and then compare the resulting QSharedPointers.") bool operator!=(const QSharedPointer &o) const noexcept { return !(*this == o); } template + QT_DEPRECATED_VERSION_X_6_7("Comparison of QWeakPointers is inconsistent and may lead to crashes. lock() them and then compare the resulting QSharedPointers.") friend bool operator==(const QSharedPointer &p1, const QWeakPointer &p2) noexcept { return p2 == p1; } template + QT_DEPRECATED_VERSION_X_6_7("Comparison of QWeakPointers is inconsistent and may lead to crashes. lock() them and then compare the resulting QSharedPointers.") friend bool operator!=(const QSharedPointer &p1, const QWeakPointer &p2) noexcept { return p2 != p1; } +#endif friend bool operator==(const QWeakPointer &p, std::nullptr_t) { return p.isNull(); }