Delete the QSlotObject when disconnect()ing
When disconnect()ing through a QMetaObject::Connection, if the QObjectPrivate::Connection contains a slot object, deref it, so that it will be destroyed before the next run of cleanConnectionList. Previously, a copy of the functor passed to connect() was kept until QObjectPrivate::cleanConnectionLists was called (by adding a new signal, or the sender was destroyed), even after a successful call to disconnect(). That is, we were keeping that copy allocated without any good reason. Change-Id: Ie6074ea797df1611cb995dec07c5b5a742360833 Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
This commit is contained in:
parent
c4f433d581
commit
cc89509f83
@ -4294,6 +4294,12 @@ bool QObject::disconnect(const QMetaObject::Connection &connection)
|
||||
c->next->prev = c->prev;
|
||||
c->receiver = 0;
|
||||
|
||||
// destroy the QSlotObject, if possible
|
||||
if (c->isSlotObject) {
|
||||
c->slotObj->destroyIfLastRef();
|
||||
c->isSlotObject = false;
|
||||
}
|
||||
|
||||
const_cast<QMetaObject::Connection &>(connection).d_ptr = 0;
|
||||
c->deref(); // has been removed from the QMetaObject::Connection object
|
||||
|
||||
|
@ -5594,12 +5594,8 @@ void tst_QObject::disconnectDoesNotLeakFunctor()
|
||||
QVERIFY(c);
|
||||
QCOMPARE(countedStructObjectsCount, 2);
|
||||
QVERIFY(QObject::disconnect(c));
|
||||
// the connection list has been marked dirty, but not cleaned yet.
|
||||
QCOMPARE(countedStructObjectsCount, 2);
|
||||
QCOMPARE(countedStructObjectsCount, 1);
|
||||
}
|
||||
// disconnect() dropped the reference that c had to the functor;
|
||||
// the sender has been destroyed. Therefore, the QObjectPrivate::Connection
|
||||
// refcount dropped to zero and destroyed the functor.
|
||||
QCOMPARE(countedStructObjectsCount, 0);
|
||||
}
|
||||
QCOMPARE(countedStructObjectsCount, 0);
|
||||
@ -5616,11 +5612,46 @@ void tst_QObject::disconnectDoesNotLeakFunctor()
|
||||
QVERIFY(c2);
|
||||
QCOMPARE(countedStructObjectsCount, 2);
|
||||
QVERIFY(QObject::disconnect(c1));
|
||||
// the connection list has been marked dirty, but not cleaned yet.
|
||||
QCOMPARE(countedStructObjectsCount, 2);
|
||||
// functor object has been destroyed
|
||||
QCOMPARE(countedStructObjectsCount, 1);
|
||||
}
|
||||
// c2 still holds a reference; c1 has been cleaned up
|
||||
QCOMPARE(countedStructObjectsCount, 0);
|
||||
}
|
||||
QCOMPARE(countedStructObjectsCount, 0);
|
||||
{
|
||||
CountedStruct s;
|
||||
QCOMPARE(countedStructObjectsCount, 1);
|
||||
QTimer timer;
|
||||
|
||||
QMetaObject::Connection c = connect(&timer, &QTimer::timeout, s);
|
||||
QVERIFY(c);
|
||||
QCOMPARE(countedStructObjectsCount, 2);
|
||||
QVERIFY(QObject::disconnect(c));
|
||||
QCOMPARE(countedStructObjectsCount, 1);
|
||||
}
|
||||
QCOMPARE(countedStructObjectsCount, 0);
|
||||
{
|
||||
QTimer timer;
|
||||
|
||||
QMetaObject::Connection c = connect(&timer, &QTimer::timeout, CountedStruct());
|
||||
QVERIFY(c);
|
||||
QCOMPARE(countedStructObjectsCount, 1); // only one instance, in Qt internals
|
||||
QVERIFY(QObject::disconnect(c));
|
||||
QCOMPARE(countedStructObjectsCount, 0); // functor being destroyed
|
||||
}
|
||||
QCOMPARE(countedStructObjectsCount, 0);
|
||||
{
|
||||
#if defined(Q_COMPILER_LAMBDA)
|
||||
CountedStruct s;
|
||||
QCOMPARE(countedStructObjectsCount, 1);
|
||||
QTimer timer;
|
||||
|
||||
QMetaObject::Connection c = connect(&timer, &QTimer::timeout, [s](){});
|
||||
QVERIFY(c);
|
||||
QCOMPARE(countedStructObjectsCount, 2);
|
||||
QVERIFY(QObject::disconnect(c));
|
||||
QCOMPARE(countedStructObjectsCount, 1);
|
||||
#endif // Q_COMPILER_LAMBDA
|
||||
}
|
||||
QCOMPARE(countedStructObjectsCount, 0);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user