Qt析构函数调用已关闭的小部件

时间:2011-08-17 11:09:07

标签: c++ qt memory-management destructor

有应用程序处理文本命令。我有一个用一些close *命令关闭的Qt小部件。为该窗口小部件设置了Qt::WA_DeleteOnClose属性,它接收到closeEvent,但稍后会调用该对象的析构函数(我想在空闲时)。如果我有两个命令 close *; get something;程序崩溃,因为在该窗口小部件的析构函数之前调用get something,因此它尝试访问close *命令删除的数据。我如何强迫Qt调用析构函数?关闭命令后QCoreApplication::processEvents()无效。 将qt版本从4.3.3更改为4.7.2后,我遇到了这个问题。这里没有多线程。

提前致谢。

加入

这是代码示例。

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;

测试类派生自QDialog。它在构造函数中打印test(),在析构函数中打印~test()。此代码提供以下输出

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

根据Qt文档,它应该在最后一个cout之前删除对象,对吗?看起来像Qt中的一个错误,有人知道吗?任何解决方法?

我在Qt邮件列表中询问了这个问题,但仍在等待答案。

感谢。

再次更新

此代码

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();
}

打印此

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

但是只要我在该处理程序函数中添加了closeEvent处理程序并调用deleteLater(),sendPostedEvents就会开始删除延迟对象。

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

打印出来     在sendPostedEvents()之前     〜测试()     在sendPostedEvents()之后

有人可以解释那里到底发生了什么吗?这只是一个错误吗?我可以将其用作解决方法吗?

这是如何工作的?如果设置了CloseOnDelete属性,那么在接受closeEvent后,Qt是否应自动调用deleteLater()?

2 个答案:

答案 0 :(得分:7)

设置Qt::WA_DeleteOnClose表示qt可以在您致电close()后随时删除,因为qt在内部使用deleteLater()。您可以使用QObject::destroyed()信号确保删除。

答案 1 :(得分:1)

QCoreApplication :: processEvents在关闭事件时显式跳过删除。您需要将QEventLoop :: DeferredDeletion传递给processEvents()。即QCoreApplication :: processEvents(QEventLoop :: DeferredDeletion);