QObject :: deleteLater не вызывается, как ожидалось в моем тесте Qt - PullRequest
0 голосов
/ 19 сентября 2018

Я тестирую разделяемую библиотеку, которая содержит внутренний вызов 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");
}

Класс 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);
  }
};

Я добавил отладочную печать в dtor m_obj, и онне вызывается при выполнении test1.

Однако, если я выполню тест дважды (добавив слот test2, являющийся копией test1), он будет вызван один раз.

Мое пониманиеявляется то, что когда сигнал испускается, он останавливает цикл шпионских событий, а затем deleteLater никогда не вызывается.И после этого второй цикл обработки событий запускается в test2, он обрабатывает ожидающее удаление из предыдущего test1.

Это правильно?Спасибо.

1 Ответ

0 голосов
/ 19 сентября 2018

Да, вы правы.Поскольку QSignalSpy и Foo находятся в одном потоке, сигнал mySignal доставляется не через цикл обработки событий, а через прямое соединение.Таким образом, цикл обработки событий останавливается сразу после того, как сигнал излучается в myslot.Однако, поскольку myslot был вызван тем же циклом событий, управление возвращается к нему только тогда, когда myslot возвращается.Таким образом, к тому времени, когда цикл обработки событий потенциально может выполнить очистку, запрошенную deleteLater, он уже был остановлен.

Если вы хотите проверить правильность очистки m_obj, вы можете вместо этого создать дополнительный QSignalSpy и подключить его к сигналу QObject::destroyed, который выдает каждый QObject при его уничтожении.

Однако вам нужно было бы передать 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");
}
...