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<T> that is the last owning pointer to T
  and a QWeakPointer<T> 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 <thiago.macieira@intel.com>
This commit is contained in:
Giuseppe D'Angelo 2023-09-28 15:52:06 +02:00
parent f2e19d37de
commit bb23a05905

View File

@ -652,28 +652,36 @@ public:
// std::weak_ptr compatibility:
[[nodiscard]] QSharedPointer<T> lock() const { return toStrongRef(); }
#if QT_DEPRECATED_SINCE(6, 7)
template <class X>
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<X> &o) const noexcept
{ return d == o.d && value == static_cast<const T *>(o.value); }
template <class X>
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<X> &o) const noexcept
{ return !(*this == o); }
template <class X>
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<X> &o) const noexcept
{ return d == o.d; }
template <class X>
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<X> &o) const noexcept
{ return !(*this == o); }
template <typename X>
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<X> &p1, const QWeakPointer &p2) noexcept
{ return p2 == p1; }
template <typename X>
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<X> &p1, const QWeakPointer &p2) noexcept
{ return p2 != p1; }
#endif
friend bool operator==(const QWeakPointer &p, std::nullptr_t)
{ return p.isNull(); }