QObject::deleteLater 在我的 Qt 测试中没有按预期调用
QObject::deleteLater is not called as expected in my Qt Test
我正在测试一个共享库,其中包含对 deleteLater
的内部调用。
库中没有事件循环运行,因此应用程序的要求是有一个事件循环运行,以便所有内存都被正确释放。
但是在测试中,对象dtor没有按预期调用。
例如:
void test1()
{
Foo foo;
QSignalSpy spy(&foo, SIGNAL(mySignal(Status)));
foo.do(); // should trigger mySignal
QVERIFY(spy.wait(10000)); // event loop started for 10 s max
QCOMPARE(spy.count(), 1);
QList<QVariant> sig = spy.takeFirst();
Foo::Status status = qvariant_cast<Foo::Status>(sig.at(0));
QVERIFY2(status == Foo:Ok, "Failed");
}
class Foo
看起来像这样:
class Foo : public QObject
{
Q_OBJECT
// ... methods, signals, slots..
private slots:
// this call is asynchronous (depends on a network reply)
void myslot() {
//..
m_obj->deleteLater();
emit mySignal(Foo:Ok);
}
};
我在m_obj的dtor中添加了一些调试打印,并且在执行test1时没有调用它。
但是,如果我执行两次测试(通过添加一个 test2 插槽,它是 test1 的副本),那么它会被调用一次。
我的理解是,当发出信号时,它会停止间谍事件循环,然后永远不会调用 deleteLater
。
之后,第二个事件循环在 test2 中开始,它处理来自前一个 test1 的未决删除。
是否正确?
谢谢。
是的,你是对的。由于 QSignalSpy
和 Foo
位于同一个线程中,因此信号 mySignal
不是通过事件循环传递的,而是通过直接连接传递的。因此,事件循环在 myslot
中发出信号后立即停止。但是,由于 myslot
被同一个事件循环调用,因此当 myslot
returns 时,仅控制 returns 到它。因此,当事件循环可能执行 deleteLater
请求的清理时,它已经停止了。
如果你想测试 m_obj
是否被正确清理,你可以创建一个额外的 QSignalSpy
并将其连接到每个 QObject
发出的 QObject::destroyed
信号当它被摧毁时。
但是,您需要在构造函数中或通过 setter 将 m_obj
作为对 Foo
的依赖项传递,而不是在 Foo
中构造它本身。
测试可能看起来像这样:
void test1()
{
auto obj = new Obj{}; // will be assigned to `Foo::m_obj`
Foo foo{obj};
QSignalSpy deletion_spy(obj, &QObject::destroyed);
QSignalSpy mysignal_spy(&Foo, &Foo::mySignal);
QVERIFY(deletion_spy.wait(10000));
QCOMPARE(deletion_spy.count(), 1); // verify that `obj` got deleted
QCOMPARE(mysignal_spy.count(), 1);
QList<QVariant> sig = spy.takeFirst();
Foo::Status status = qvariant_cast<Foo::Status>(sig.at(0));
QVERIFY2(status == Foo:Ok, "Failed");
}
我正在测试一个共享库,其中包含对 deleteLater
的内部调用。
库中没有事件循环运行,因此应用程序的要求是有一个事件循环运行,以便所有内存都被正确释放。
但是在测试中,对象dtor没有按预期调用。
例如:
void test1()
{
Foo foo;
QSignalSpy spy(&foo, SIGNAL(mySignal(Status)));
foo.do(); // should trigger mySignal
QVERIFY(spy.wait(10000)); // event loop started for 10 s max
QCOMPARE(spy.count(), 1);
QList<QVariant> sig = spy.takeFirst();
Foo::Status status = qvariant_cast<Foo::Status>(sig.at(0));
QVERIFY2(status == Foo:Ok, "Failed");
}
class Foo
看起来像这样:
class Foo : public QObject
{
Q_OBJECT
// ... methods, signals, slots..
private slots:
// this call is asynchronous (depends on a network reply)
void myslot() {
//..
m_obj->deleteLater();
emit mySignal(Foo:Ok);
}
};
我在m_obj的dtor中添加了一些调试打印,并且在执行test1时没有调用它。
但是,如果我执行两次测试(通过添加一个 test2 插槽,它是 test1 的副本),那么它会被调用一次。
我的理解是,当发出信号时,它会停止间谍事件循环,然后永远不会调用 deleteLater
。
之后,第二个事件循环在 test2 中开始,它处理来自前一个 test1 的未决删除。
是否正确? 谢谢。
是的,你是对的。由于 QSignalSpy
和 Foo
位于同一个线程中,因此信号 mySignal
不是通过事件循环传递的,而是通过直接连接传递的。因此,事件循环在 myslot
中发出信号后立即停止。但是,由于 myslot
被同一个事件循环调用,因此当 myslot
returns 时,仅控制 returns 到它。因此,当事件循环可能执行 deleteLater
请求的清理时,它已经停止了。
如果你想测试 m_obj
是否被正确清理,你可以创建一个额外的 QSignalSpy
并将其连接到每个 QObject
发出的 QObject::destroyed
信号当它被摧毁时。
但是,您需要在构造函数中或通过 setter 将 m_obj
作为对 Foo
的依赖项传递,而不是在 Foo
中构造它本身。
测试可能看起来像这样:
void test1()
{
auto obj = new Obj{}; // will be assigned to `Foo::m_obj`
Foo foo{obj};
QSignalSpy deletion_spy(obj, &QObject::destroyed);
QSignalSpy mysignal_spy(&Foo, &Foo::mySignal);
QVERIFY(deletion_spy.wait(10000));
QCOMPARE(deletion_spy.count(), 1); // verify that `obj` got deleted
QCOMPARE(mysignal_spy.count(), 1);
QList<QVariant> sig = spy.takeFirst();
Foo::Status status = qvariant_cast<Foo::Status>(sig.at(0));
QVERIFY2(status == Foo:Ok, "Failed");
}