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>
This commit is contained in:
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
Block a user