我最近一直在尝试进入Qt,以更好地理解类层次结构和OOP。我只是在测试银行遇到这个问题,要求“修复”此代码以防止编译器和运行时错误。但是,很遗憾,我找不到解决方案,而且我自己也无法提出解决方案。对我来说,所有QObject派生的类都处理所有内存释放。因此,以下代码不会引起我看到的任何问题,并且可以编译。
#include <QLabel>
#include <QWidget>
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QLabel label("my string");
QWidget window;
label.setParent(&window);
window.show();
return a.exec();
}
对我来说,所有QObject派生的类都处理所有内存的重新分配。
正是这就是为什么此示例代码包含当您关闭window
时会看到的那种错误。 Qt的父子系统以小部件管理其子寿命的方式工作,并在自身被删除时将其删除。
因此,当QApplication
退出时,将调用~QWidget()
析构函数,从而导致label
的删除。因此,将调用~QLabel()
。
但是,另一方面,当main
完成时,将删除局部变量,label
是其中之一。它不是指针,而是值变量,我们再次调用~QLabel()
。
析构函数的两次调用是错误。可以通过通过label
在堆上创建new
来解决。
Qt通过父子关系处理内存管理。如果父窗口小部件/窗口被销毁,它也将销毁所有子窗口/窗口。在这种情况下,标签设置为窗口的子级,这意味着Windows析构函数将尝试删除它。当它在堆栈上创建时,内存释放将失败。并且即使不这样做,main()
的执行完成时,标签也会第二次被破坏,从而导致两次删除。正如其他人已经指出的那样,您可以通过使用QLabel *label = new QLabel("my string");
在堆上分配标签来解决此问题,但是还有一个更简单的解决方案:重新排列窗口和标签的创建顺序: