我是Qt的新手。所以我开始重新实现一个入门示例:link。
然而,关闭窗口时我收到SIGABRT信号。其原因很明显是由于一些内存管理错误。
您可以在下面找到callstack和相关代码。行editWindow.setLayout(&layout);
导致错误。布局类是否在销毁时删除小部件,因此声称对它们拥有所有权?
这种行为的原因是什么?以及如何解决它?
最好的问候。
信息
调用堆栈
源
QPushButton testButton("Test");
QVBoxLayout layout;
layout.addWidget(&testButton);
QWidget editWindow;
// the following line is the source of the error
editWindow.setLayout(&layout);
editWindow.show();
int val = app.exec();
答案 0 :(得分:7)
许多不同的Qt函数将获取所传递对象的所有权,这意味着它将控制所有内存管理并在删除时释放它。来自setLayout文档:
QWidget将获得布局的所有权。
调用setLayout
后,它有一个父项,除了在清除方法堆栈时删除它之外,它的父项将删除它。因此,它被删除两次导致问题。
如果其他一切都正确,这个改变应该解决它:
QVBoxLayout *layout = new QVBoxLayout();
//...
layout->addWidget(&testButton);
//...
editWindow.setLayout(layout);
另外,请注意,创建主窗口小部件然后分配将在该窗口小部件上显示为父窗口的窗口小部件是典型的。换句话说,我希望更像下面的东西(尽管不是绝对必要的)。这也有助于确保如果某些事情在未来得到重新定位,您将不会遇到问题:
QWidget editWindow;
QVBoxLayout *layout = new QVBoxLayout();
QPushButton *testButton = new QPushButton(&editWindow);
layout->addWidget(testButton);
editWindow.setLayout(layout);
editWindow.show();
int val = app.exec();
大多数重新定位的Qt对象以及可能发生的所有权更改都会有一个接受QWidget*
或QObject*
的构造函数。
答案 1 :(得分:2)
QWidget
期望通过operator new创建布局实例并获取实例的所有权,在QWidget
被销毁时调用delete(see documentation)。因此,你需要的是这样的东西:
QVBoxLayout *layout = new QVBoxLayout();
/// ...
editWindow.setLayout(layout);
所有权同样适用于您的testButton。
答案 2 :(得分:1)
示例代码似乎是错误的(奇怪的是)。 QWidget
的析构函数在其布局上调用delete
。在您的情况下,QVBoxLayout
实例已在堆栈而不是堆上创建,因此在该指针上调用delete
无效将中止该应用程序。
同样适用于QObject
的所有孩子。当QObject
被删除时,它会在其所有子节点上调用delete
,如果这些子节点已在堆栈上创建,它将以相同的方式失败。
现在,要了解为什么诺基亚发布了这么糟糕的例子......