C++ 为什么此QT应用程序会以SIGABRT信号退出?

C++ 为什么此QT应用程序会以SIGABRT信号退出?,c++,opengl,qt4,sigabrt,C++,Opengl,Qt4,Sigabrt,我是新来的。所以我开始重新实现一个入门示例: 然而,我在关窗时收到了一个信号。原因很明显是内存管理错误 下面是callstack和相关代码。行editWindow.setLayout(&layout)导致错误。layout类是否在销毁时删除小部件,从而声明它们的所有权 这种行为的原因是什么?如何修复它 致以最良好的祝愿 信息 调用堆栈 来源 QWidget需要通过operator new创建一个布局实例,并获得该实例的所有权,当QWidget被销毁时调用delete()。因此,您需要的是以下内

我是新来的。所以我开始重新实现一个入门示例:

然而,我在关窗时收到了一个信号。原因很明显是内存管理错误

下面是callstack和相关代码。行
editWindow.setLayout(&layout)导致错误。layout类是否在销毁时删除小部件,从而声明它们的所有权

这种行为的原因是什么?如何修复它

致以最良好的祝愿

信息
调用堆栈

来源


QWidget
需要通过operator new创建一个布局实例,并获得该实例的所有权,当
QWidget
被销毁时调用delete()。因此,您需要的是以下内容:

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

所有权同样适用于testButton。

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

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


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

许多不同的Qt函数将拥有传入的对象,这意味着它将控制所有内存管理,并在删除时释放它。从文档中:

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*

布局不拥有按钮的所有权,因此该部分应该没有问题。。。但是,您必须小心,不要做会重新分配小部件并控制其清理的事情。根据文档,布局的addWidget方法使用内部addItem,它获取传递实例的所有权,请参阅。文档实际上说,“项的所有权转移到布局。”并且项是由函数参数定义的
QLayoutItem
,而不是传递给
addWidget
的QWidget。尽管我从未明确测试过这一点,但我从未见过任何相反的情况。如果您测试并发现其他问题,请让我知道。请注意,每个小部件都将被重新租给布局的父部件,如果小部件并没有父部件。
QWidget editWindow;
QVBoxLayout *layout = new QVBoxLayout();
QPushButton *testButton = new QPushButton(&editWindow);
layout->addWidget(testButton);
editWindow.setLayout(layout);
editWindow.show();
int val = app.exec();