From c5a27f4cfee9aa1f440625b67f03f3f3188017ed Mon Sep 17 00:00:00 2001 From: Tim Blechmann Date: Wed, 7 Aug 2024 13:57:42 +0800 Subject: [PATCH] QObject: disconnect - document behavior with queued connections QObject::disconnect does not cancel pending events. This can cause hard to find bugs in application code, so we explicitly document and unit test this behavior. Task-number: QTBUG-127675 Change-Id: I5e94d60c27b9ce2dd2bceb832eb817b7eaa9cdcd Reviewed-by: Marc Mutz Reviewed-by: Leena Miettinen Reviewed-by: Thiago Macieira (cherry picked from commit 0681e720a9851f1873ce5a5f99b5567d2b418261) Reviewed-by: Qt Cherry-pick Bot --- src/corelib/doc/src/includes/qobject.qdocinc | 6 ++++++ src/corelib/kernel/qobject.cpp | 4 ++++ .../auto/corelib/kernel/qobject/tst_qobject.cpp | 17 +++++++++++++++++ 3 files changed, 27 insertions(+) diff --git a/src/corelib/doc/src/includes/qobject.qdocinc b/src/corelib/doc/src/includes/qobject.qdocinc index d3607582e92..9e09e158bc2 100644 --- a/src/corelib/doc/src/includes/qobject.qdocinc +++ b/src/corelib/doc/src/includes/qobject.qdocinc @@ -17,3 +17,9 @@ calls. To avoid mismatches, store the connection handle returned by connect(), and use it in the call to \l{disconnect(const QMetaObject::Connection &connection)}{disconnect()}. //! [disconnect-mismatch] + +//! [disconnect-queued] +\note If a \l{Qt::QueuedConnection}{queued connection} is disconnected, +already scheduled events may still be delivered, causing the receiver to +be called after the connection is disconnected. +//! [disconnect-queued] diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 92bdb26e660..aef644a0ec7 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -3210,6 +3210,7 @@ QMetaObject::Connection QObject::connect(const QObject *sender, const QMetaMetho \endlist \include includes/qobject.qdocinc disconnect-mismatch + \include includes/qobject.qdocinc disconnect-queued \nullptr may be used as a wildcard, meaning "any signal", "any receiving object", or "any slot in the receiving object", respectively. @@ -3364,6 +3365,7 @@ bool QObject::disconnect(const QObject *sender, const char *signal, \endlist \include includes/qobject.qdocinc disconnect-mismatch + \include includes/qobject.qdocinc disconnect-queued QMetaMethod() may be used as wildcard in the meaning "any signal" or "any slot in receiving object". In the same way \nullptr can be used for \a receiver in the meaning "any receiving object". @@ -3439,6 +3441,7 @@ bool QObject::disconnect(const QObject *sender, const QMetaMethod &signal, Disconnects \a signal from \a method of \a receiver. \include includes/qobject.qdocinc disconnect-mismatch + \include includes/qobject.qdocinc disconnect-queued A signal-slot connection is removed when either of the objects involved are destroyed. @@ -3454,6 +3457,7 @@ bool QObject::disconnect(const QObject *sender, const QMetaMethod &signal, method. \include includes/qobject.qdocinc disconnect-mismatch + \include includes/qobject.qdocinc disconnect-queued A signal-slot connection is removed when either of the objects involved are destroyed. diff --git a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp index 4f36e142794..ef8af81dcef 100644 --- a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp +++ b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp @@ -155,6 +155,7 @@ private slots: void emitToDestroyedClass(); void declarativeData(); void asyncCallbackHelper(); + void disconnectQueuedConnection_pendingEventsAreDelivered(); }; struct QObjectCreatedOnShutdown @@ -8949,5 +8950,21 @@ void tst_QObject::asyncCallbackHelper() } } +void tst_QObject::disconnectQueuedConnection_pendingEventsAreDelivered() +{ + SenderObject sender; + ReceiverObject receiver; + + receiver.count_slot1 = 0; + QObject::connect(&sender, &SenderObject::signal1, &receiver, &ReceiverObject::slot1, + Qt::QueuedConnection); + sender.emitSignal1(); + QCOMPARE(receiver.count_slot1, 0); + + QObject::disconnect(&sender, &SenderObject::signal1, &receiver, &ReceiverObject::slot1); + QCOMPARE(receiver.count_slot1, 0); + QTRY_COMPARE(receiver.count_slot1, 1); +} + QTEST_MAIN(tst_QObject) #include "tst_qobject.moc"