Qt destructor call for closed widget

2019-03-27 09:15发布

问题:

There is application that handles text commands. I have a Qt widget that is closed with some close * command. Qt::WA_DeleteOnClose attribute is set for that widget, it receives closeEvent, but destructor for that object is called later (I guess on idle). If I have two commands close *; get something; the program crashes because get something is called before destructor for that widget, so it tries to access data deleted by close * command. How can I force Qt to call destructors? QCoreApplication::processEvents() after close command doesn't help. I've got this problem after changing qt version to 4.7.2 from 4.3.3. There is no multithreading here.

Thanks in advance.

added

Here is the code example.

test *t = new test();
t->show();
std::cout << "before deleteLater()" << std::endl;
t->deleteLater();
std::cout << "after deleteLater()" << std::endl;
QCoreApplication::sendPostedEvents();
QCoreApplication::processEvents();
std::cout << "after processEvents()" << std::endl;

test class is derived from QDialog. It prints test() in constructor and ~test() in destructor. This code gives the following output

test()
before deleteLater()
after deleteLater()
after processEvents()
~test()

According to Qt documentation it should delete the object before last cout, am I right? Looks like a bug in Qt, does anybody know anything about it? Any workaround?

I asked the question in Qt mailing list, but still waiting for an answer.

Thanks.

one more update

This code

Dialog::~Dialog() {
    std::cout << "~test()" << std::endl;
}

int main(int argc, char* argv[]) {
    QApplication app(argc, argv);
    Dialog* dlg = new Dialog();
    dlg->setAttribute(Qt::WA_DeleteOnClose);
    dlg->show();
    dlg->close();
    std::cout << "before sendPostedEvents()" << std::endl;
    QCoreApplication::sendPostedEvents();
    std::cout << "after sendPostedEvents()" << std::endl;
    return app.exec();
}

prints this

before sendPostedEvents()
after sendPostedEvents()
~test()

but as soon as I add closeEvent handler and call deleteLater() in that handler function sendPostedEvents starts deleting deferred objects.

void Dialog::closeEvent(QCloseEvent* ev) {
    deleteLater();
    QWidget::closeEvent(ev);
}

prints this before sendPostedEvents() ~test() after sendPostedEvents()

Can anybody explain what the hell is going on there? Is it just a bug? Can I use that as a workaround?

How does this work? Shouldn't Qt call deleteLater() automatically, after closeEvent is accepted if CloseOnDelete attribute is set?

回答1:

Setting Qt::WA_DeleteOnClose means qt can delete anytime after you call close() because qt uses deleteLater() internally. You can ensure the deletion using QObject::destroyed() signal.



回答2:

QCoreApplication::processEvents explicitly skips delete on close events. You need to pass QEventLoop::DeferredDeletion to processEvents(). i.e. QCoreApplication::processEvents(QEventLoop::DeferredDeletion);