diff options
author | Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> | 2023-09-23 18:06:15 +0200 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2023-09-25 12:04:42 +0000 |
commit | 2561158bc6eba4e39153658b0b843e9471ea9db0 (patch) | |
tree | 8678afc4c62f7ee77fd9527d0c2180f5f889eba5 | |
parent | 2f9c7ca99a4daddfd6169f6fb0e9dcd1447324ac (diff) |
QPointer: also provide a converting assignment operator
d026fad3d962eed0119351cd37f34490e09153fd added converting constructors
for QPointer. This however made converting _assignments_ ambiguous,
introducing a regression for users coming from Qt < 6.6.
This code:
QPointer<Base> base;
QPointer<Derived> derived;
base = derived;
used to convert `derived` to `Derived *` (using the implicit conversion
operator from `QPointer<Derived>` to `Derived *`), and then the
assignment operator for `QPointer<Base>` that took a `Base *`.
The introduction of the conversion constructor in 6.6 makes it possible
to convert `QPointer<Derived>` to `QPointer<Base>`, and then fall back
to the compiler-generated assignment operator for `QPointer<Base>`.
The result is that the code above is now ambiguous and stops compiling.
Fix this by adding a converting assignment operator for QPointer.
I'm only adding the const-lvalue overload because the implementation
requires going through the private QWeakPointer::assign helper. We
cannot copy-assign or move-assign the inner QWeakPointer, as those
assignments require lock()ing the QWeakPointer and that's not possible
on a QObject-tracking QWeakPointer (but cf. QTBUG-117483).
Assigning from a rvalue QPointer would mean calling assign() on
the internal QWeakPointer _and_ clear the incoming QPointer,
and that's strictly worse than the lvalue overload (where we just call
assign()).
Change-Id: I33fb2a22b3d5110284d78e3d7c6cc79a5b73b67b
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
(cherry picked from commit 6c504f2519e1180dbcfd77d5bb08b0db9742eeaa)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
(cherry picked from commit 11aa3b13b3edb3c8731ad45b8e475c6037ffce97)
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
-rw-r--r-- | src/corelib/kernel/qpointer.cpp | 11 | ||||
-rw-r--r-- | src/corelib/kernel/qpointer.h | 7 | ||||
-rw-r--r-- | tests/auto/corelib/kernel/qpointer/tst_qpointer.cpp | 23 |
3 files changed, 41 insertions, 0 deletions
diff --git a/src/corelib/kernel/qpointer.cpp b/src/corelib/kernel/qpointer.cpp index c884844db3..e426c63ae5 100644 --- a/src/corelib/kernel/qpointer.cpp +++ b/src/corelib/kernel/qpointer.cpp @@ -112,6 +112,17 @@ */ /*! + \fn template <class T> template <class X> QPointer<T> &QPointer<T>::operator=(const QPointer<X> &other) + \since 6.6 + + Conversion assignment operator. Makes this guarded pointer guard the + same object guarded by \a other. + + \note This operator participates in overload resolution only if \c{X*} + is convertible to \c{T*}. +*/ + +/*! \fn template <class T> void QPointer<T>::swap(QPointer &other) \since 5.6 diff --git a/src/corelib/kernel/qpointer.h b/src/corelib/kernel/qpointer.h index 1914c45190..7de159a535 100644 --- a/src/corelib/kernel/qpointer.h +++ b/src/corelib/kernel/qpointer.h @@ -43,6 +43,13 @@ public: QPointer(const QPointer<X> &other) noexcept : wp(other.wp.internalData(), true) {} + template <typename X, if_convertible<X> = true> + QPointer &operator=(const QPointer<X> &other) + { + wp.assign(other.data()); + return *this; + } + #ifdef Q_QDOC // Stop qdoc from complaining about missing function ~QPointer(); diff --git a/tests/auto/corelib/kernel/qpointer/tst_qpointer.cpp b/tests/auto/corelib/kernel/qpointer/tst_qpointer.cpp index 332cf6ab71..7f01c6f964 100644 --- a/tests/auto/corelib/kernel/qpointer/tst_qpointer.cpp +++ b/tests/auto/corelib/kernel/qpointer/tst_qpointer.cpp @@ -57,6 +57,19 @@ void tst_QPointer::conversion() QCOMPARE_EQ(pio.get(), &file); QCOMPARE_EQ(pio, pf); QCOMPARE_EQ(pio.get(), pf.get()); + + // reset + pio = nullptr; + QCOMPARE_EQ(pio, nullptr); + QCOMPARE_EQ(pio.get(), nullptr); + + // copy-assignment + QCOMPARE_EQ(pf, &file); + pio = pf; + QCOMPARE_EQ(pio, &file); + QCOMPARE_EQ(pio.get(), &file); + QCOMPARE_EQ(pio, pf); + QCOMPARE_EQ(pio.get(), pf.get()); } // move-conversion: { @@ -67,6 +80,16 @@ void tst_QPointer::conversion() QCOMPARE_EQ(pf, nullptr); QCOMPARE_EQ(pio, &file); QCOMPARE_EQ(pio.get(), &file); + + // reset + pio = nullptr; + QCOMPARE_EQ(pio, nullptr); + QCOMPARE_EQ(pio.get(), nullptr); + + // move-assignment + pio = QPointer<QFile>(&file); + QCOMPARE_EQ(pio, &file); + QCOMPARE_EQ(pio.get(), &file); } } |