Make QMetaObject::Connection check its state deeply
Since Connection can be copied, one copy could be used for
disconnecting, but the other's d_ptr wouldn't get updated and would
continue to report as still connected.
This patch fixes that by making it check the internal state. That is
only done after d_ptr is already known to be non-null. Unfortunately,
that is the common path:
if (connect(sender, &Sender::signal, [] {}))
will call an out-of-line function. I don't see a way out.
Task-number: QTBUG-46213
Change-Id: I66a35ce5f88941f29aa6ffff13dfb45dca68a350
Reviewed-by: Olivier Goffart (Woboq GmbH) <ogoffart@woboq.com>
bb10
parent
54589f2932
commit
b2be272d35
|
|
@ -4913,6 +4913,16 @@ QMetaObject::Connection::~Connection()
|
|||
static_cast<QObjectPrivate::Connection *>(d_ptr)->deref();
|
||||
}
|
||||
|
||||
/*! \internal Returns true if the object is still connected */
|
||||
bool QMetaObject::Connection::isConnected_helper() const
|
||||
{
|
||||
Q_ASSERT(d_ptr); // we're only called from operator RestrictedBool() const
|
||||
QObjectPrivate::Connection *c = static_cast<QObjectPrivate::Connection *>(d_ptr);
|
||||
|
||||
return c->receiver;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
\fn QMetaObject::Connection::operator bool() const
|
||||
|
||||
|
|
|
|||
|
|
@ -472,6 +472,7 @@ class Q_CORE_EXPORT QMetaObject::Connection {
|
|||
friend class QObject;
|
||||
friend class QObjectPrivate;
|
||||
friend struct QMetaObject;
|
||||
bool isConnected_helper() const;
|
||||
public:
|
||||
~Connection();
|
||||
Connection();
|
||||
|
|
@ -481,7 +482,7 @@ public:
|
|||
operator bool() const;
|
||||
#else
|
||||
typedef void *Connection::*RestrictedBool;
|
||||
operator RestrictedBool() const { return d_ptr ? &Connection::d_ptr : 0; }
|
||||
operator RestrictedBool() const { return d_ptr && isConnected_helper() ? &Connection::d_ptr : 0; }
|
||||
#endif
|
||||
|
||||
#ifdef Q_COMPILER_RVALUE_REFS
|
||||
|
|
|
|||
|
|
@ -918,6 +918,8 @@ void tst_QObject::connectDisconnectNotifyPMF()
|
|||
QMetaObject::Connection conn = connect((SenderObject*)s, &SenderObject::signal1,
|
||||
(ReceiverObject*)r, &ReceiverObject::slot1);
|
||||
|
||||
QVERIFY(conn);
|
||||
|
||||
// Test disconnectNotify when disconnecting by QMetaObject::Connection
|
||||
QVERIFY(QObject::disconnect(conn));
|
||||
// disconnectNotify() is not called, but it probably should be.
|
||||
|
|
@ -5751,7 +5753,6 @@ void tst_QObject::connectFunctorWithContext()
|
|||
{
|
||||
int status = 1;
|
||||
SenderObject obj;
|
||||
QMetaObject::Connection handle;
|
||||
ContextObject *context = new ContextObject;
|
||||
QEventLoop e;
|
||||
|
||||
|
|
@ -6058,8 +6059,12 @@ void tst_QObject::disconnectDoesNotLeakFunctor()
|
|||
QVERIFY(c2);
|
||||
QCOMPARE(countedStructObjectsCount, 2);
|
||||
QVERIFY(QObject::disconnect(c1));
|
||||
QVERIFY(!c1);
|
||||
QVERIFY(!c2);
|
||||
// functor object has been destroyed
|
||||
QCOMPARE(countedStructObjectsCount, 1);
|
||||
QVERIFY(!QObject::disconnect(c2));
|
||||
QCOMPARE(countedStructObjectsCount, 1);
|
||||
}
|
||||
QCOMPARE(countedStructObjectsCount, 0);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue