Qt destructor call for closed widget

2019-03-27 08:36发布

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?

2条回答
Luminary・发光体
2楼-- · 2019-03-27 09:11

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

查看更多
smile是对你的礼貌
3楼-- · 2019-03-27 09:18

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.

查看更多
登录 后发表回答