2

我是 Qt 的新手。所以我开始重新实现一个入门示例:链接

但是,我在关闭窗口时收到 SIGABRT 信号。其原因显然是由于一些内存管理错误。

您可以在下面找到调用堆栈和相关代码。该行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();
4

3 回答 3

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 对象被重新定义并且所有权可能发生变化,将有一个接受 aQWidget*或的构造函数QObject*

于 2011-07-14T16:45:16.517 回答
2

QWidget期望通过 operator new 创建的布局实例并获得实例的所有权,在QWidget销毁时调用 delete (参见文档)。因此,您需要的是这样的:

QVBoxLayout *layout = new QVBoxLayout();
/// ...
editWindow.setLayout(layout);

所有权同样适用于您的 testButton。

于 2011-07-14T16:37:20.270 回答
1

示例代码似乎是错误的(很奇怪)。a 的析构函数QWidget调用delete其布局。在您的情况下,QVBoxLayout实例是在堆栈而不是堆上创建的,因此delete对该指针的调用无效会中止应用程序。

对于 a 的所有孩子也是如此QObject。当 aQObject被删除时,它会调用它delete的所有子节点,如果这些子节点已在堆栈上创建,它将以同样的方式失败。

现在,要了解诺基亚为何发布如此糟糕的示例……

于 2011-07-14T16:40:01.390 回答