Document in a test that mixing connect/disconnect syntax doesn't work
We cannot go from member function pointer to method index for slots (we can for signals), so using string-based syntax to connect and PMF-syntax to disconnect doesn't work, and vice versa. Document this in a (partially failing) test, and add a warning to the relevant QObject::disconnect documentation. Task-number: QTBUG-126580 Task-number: QTBUG-126581 Change-Id: I4b17662aa9aa7b624049c5b0a3b046ed35230f05 Reviewed-by: Ahmad Samir <a.samirh78@gmail.com> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> (cherry picked from commit 27a3229626249a100d8e6fa495927715aba6963d) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
0fb43e4395
commit
f715325932
@ -8,3 +8,12 @@ affect classes that rely on this signal for cleaning up resources. It is
|
||||
recommended to disconnect only the specific signals that were connected by
|
||||
application code.
|
||||
//! [disconnect-all]
|
||||
|
||||
//! [disconnect-mismatch]
|
||||
\note Use the the same syntax, pointer-to-member-function or string-based using
|
||||
the \c SIGNAL and \c SLOT macros, in connect() and corresponding disconnect()
|
||||
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]
|
||||
|
@ -3210,6 +3210,8 @@ QMetaObject::Connection QObject::connect(const QObject *sender, const QMetaMetho
|
||||
|
||||
\endlist
|
||||
|
||||
\include includes/qobject.qdocinc disconnect-mismatch
|
||||
|
||||
\nullptr may be used as a wildcard, meaning "any signal", "any receiving
|
||||
object", or "any slot in the receiving object", respectively.
|
||||
|
||||
@ -3362,6 +3364,8 @@ bool QObject::disconnect(const QObject *sender, const char *signal,
|
||||
|
||||
\endlist
|
||||
|
||||
\include includes/qobject.qdocinc disconnect-mismatch
|
||||
|
||||
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".
|
||||
In this case method should also be QMetaMethod(). \a sender parameter should be never \nullptr.
|
||||
@ -3435,6 +3439,8 @@ bool QObject::disconnect(const QObject *sender, const QMetaMethod &signal,
|
||||
|
||||
Disconnects \a signal from \a method of \a receiver.
|
||||
|
||||
\include includes/qobject.qdocinc disconnect-mismatch
|
||||
|
||||
A signal-slot connection is removed when either of the objects
|
||||
involved are destroyed.
|
||||
|
||||
@ -3448,6 +3454,8 @@ bool QObject::disconnect(const QObject *sender, const QMetaMethod &signal,
|
||||
Disconnects all signals in this object from \a receiver's \a
|
||||
method.
|
||||
|
||||
\include includes/qobject.qdocinc disconnect-mismatch
|
||||
|
||||
A signal-slot connection is removed when either of the objects
|
||||
involved are destroyed.
|
||||
*/
|
||||
@ -5384,7 +5392,12 @@ bool QObject::disconnect(const QMetaObject::Connection &connection)
|
||||
\note It is not possible to use this overload to disconnect signals
|
||||
connected to functors or lambda expressions. That is because it is not
|
||||
possible to compare them. Instead, use the overload that takes a
|
||||
QMetaObject::Connection
|
||||
QMetaObject::Connection.
|
||||
|
||||
\note Unless \a method is \nullptr, this function will also not break
|
||||
connections that were made using the string-based version of connect(). To
|
||||
break such connections, use the corresponding string-based overload of
|
||||
disconnect().
|
||||
|
||||
\sa connect()
|
||||
*/
|
||||
|
@ -110,6 +110,7 @@ private slots:
|
||||
void baseDestroyed();
|
||||
void pointerConnect();
|
||||
void pointerDisconnect();
|
||||
void mixedConnectDisconnect();
|
||||
void emitInDefinedOrderPointer();
|
||||
void customTypesPointer();
|
||||
void connectCxx0x();
|
||||
@ -4852,6 +4853,125 @@ void tst_QObject::pointerDisconnect()
|
||||
QVERIFY(!r2.called(2));
|
||||
}
|
||||
|
||||
struct MixingFunctor
|
||||
{
|
||||
int index;
|
||||
void operator()() { s_called[index] = true; }
|
||||
bool called() const { return s_called[index]; }
|
||||
void reset() { s_called[index] = false; }
|
||||
|
||||
private:
|
||||
static inline bool s_called[5] = {};
|
||||
};
|
||||
|
||||
void tst_QObject::mixedConnectDisconnect()
|
||||
{
|
||||
SenderObject s;
|
||||
ReceiverObject pmf;
|
||||
ReceiverObject named;
|
||||
|
||||
MixingFunctor functor1{1};
|
||||
MixingFunctor functor2{2};
|
||||
MixingFunctor functor3{3};
|
||||
MixingFunctor functor4{4};
|
||||
|
||||
auto makePMFConnections = [sender = &s](const ReceiverObject *receiver){
|
||||
QObject::connect(sender, &SenderObject::signal1, receiver, &ReceiverObject::slot1);
|
||||
QObject::connect(sender, &SenderObject::signal2, receiver, &ReceiverObject::slot2);
|
||||
QObject::connect(sender, &SenderObject::signal3, receiver, &ReceiverObject::slot3);
|
||||
QObject::connect(sender, &SenderObject::signal4, receiver, &ReceiverObject::slot4);
|
||||
};
|
||||
auto makeNamedConnections = [sender = &s](const ReceiverObject *receiver){
|
||||
QObject::connect(sender, SIGNAL(signal1()), receiver, SLOT(slot1()));
|
||||
QObject::connect(sender, SIGNAL(signal2()), receiver, SLOT(slot2()));
|
||||
QObject::connect(sender, SIGNAL(signal3()), receiver, SLOT(slot3()));
|
||||
QObject::connect(sender, SIGNAL(signal4()), receiver, SLOT(slot4()));
|
||||
};
|
||||
|
||||
makePMFConnections(&pmf);
|
||||
makeNamedConnections(&named);
|
||||
QObject::connect(&s, &SenderObject::signal1, &named, functor1);
|
||||
QObject::connect(&s, &SenderObject::signal2, &named, functor2);
|
||||
QObject::connect(&s, &SenderObject::signal3, &named, functor3);
|
||||
QObject::connect(&s, &SenderObject::signal4, &named, functor4);
|
||||
|
||||
// sanity check
|
||||
s.emitSignal1();
|
||||
QVERIFY(pmf.called(1));
|
||||
QVERIFY(named.called(1));
|
||||
QVERIFY(functor1.called());
|
||||
pmf.reset();
|
||||
named.reset();
|
||||
functor1.reset();
|
||||
|
||||
// disconnecting a string-based connection with PMF-based disconnect doesn't work
|
||||
bool ret = false;
|
||||
ret = QObject::disconnect(&s, &SenderObject::signal1, &pmf, &ReceiverObject::slot1);
|
||||
QVERIFY(ret);
|
||||
ret = QObject::disconnect(&s, &SenderObject::signal1, &named, &ReceiverObject::slot1);
|
||||
QEXPECT_FAIL("", "Mixing PMF connect with string-based disconnect doesn't work", Continue);
|
||||
QVERIFY(ret);
|
||||
|
||||
s.emitSignal1();
|
||||
QVERIFY(!pmf.called(1));
|
||||
QEXPECT_FAIL("", "Mixing PMF connect with string-based disconnect doesn't work", Continue);
|
||||
QVERIFY(!named.called(1));
|
||||
// cannot disconnect a specific functor (or lambda)
|
||||
QVERIFY(functor1.called());
|
||||
pmf.reset();
|
||||
named.reset();
|
||||
functor1.reset();
|
||||
|
||||
// wildcard disconnect works even in mixed cases and for functor objects
|
||||
ret = QObject::disconnect(&s, SIGNAL(signal2()), &pmf, nullptr);
|
||||
QVERIFY(ret);
|
||||
ret = QObject::disconnect(&s, &SenderObject::signal2, &named, nullptr);
|
||||
QVERIFY(ret);
|
||||
|
||||
s.emitSignal2();
|
||||
QVERIFY(!pmf.called(2));
|
||||
QVERIFY(!named.called(2));
|
||||
QVERIFY(!functor2.called());
|
||||
pmf.reset();
|
||||
named.reset();
|
||||
functor2.reset();
|
||||
|
||||
ret = QObject::disconnect(&s, &SenderObject::signal3, nullptr, nullptr);
|
||||
QVERIFY(ret);
|
||||
|
||||
s.emitSignal3();
|
||||
QVERIFY(!pmf.called(3));
|
||||
QVERIFY(!named.called(3));
|
||||
QVERIFY(!functor3.called());
|
||||
pmf.reset();
|
||||
named.reset();
|
||||
functor3.reset();
|
||||
|
||||
// disconnect() member function is only available for string-based syntax
|
||||
// and doesn't disconnect PMF-based connections
|
||||
ret = s.disconnect(&pmf, SLOT(slot4()));
|
||||
QEXPECT_FAIL("", "Mixing PMF connect with string-based disconnect doesn't work", Continue);
|
||||
QVERIFY(ret);
|
||||
s.emitSignal4();
|
||||
QEXPECT_FAIL("", "Mixing PMF connect with string-based disconnect doesn't work", Continue);
|
||||
QVERIFY(!pmf.called(4));
|
||||
// the functor gets of course still called
|
||||
QVERIFY(functor4.called());
|
||||
|
||||
pmf.reset();
|
||||
named.reset();
|
||||
functor4.reset();
|
||||
|
||||
ret = s.disconnect(&named, nullptr);
|
||||
QVERIFY(ret);
|
||||
|
||||
s.emitSignal4();
|
||||
QVERIFY(!named.called(4));
|
||||
QVERIFY(!functor4.called());
|
||||
named.reset();
|
||||
functor4.reset();
|
||||
}
|
||||
|
||||
|
||||
void tst_QObject::emitInDefinedOrderPointer()
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user