为什么这个 QT 应用程序退出时带有 SIGABRT 信号?

发布于 2024-11-23 18:19:18 字数 740 浏览 2 评论 0原文

我是 Qt 新手。因此,我开始重新实现入门示例之一:链接

但是,关闭窗口时我收到 SIGABRT 信号。造成这种情况的原因显然是由于一些内存管理错误造成的。

下面您可以找到调用堆栈和相关代码。 editWindow.setLayout(&layout); 行导致错误。布局类是否在销毁时删除小部件,从而声明它们的所有权?

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

此致。

信息
调用堆栈
callstack

来源

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

I'm new to Qt. So I started to reimplement one of the get started examples: link.

However I get a SIGABRT signal when closing the windows. The reason for this is obvoisly due to some memory managment error.

Below you find the callstack and the relevant code. The line editWindow.setLayout(&layout); causes the error. Is the layout class deleting widgets on destruction, therefor claiming ownership of them?

Whats the reaon for this behavior? And how to fix it?

Best regards.

information
callstack
callstack

source

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

私藏温柔 2024-11-30 18:19:18

许多不同的 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*

Many different Qt functions will take ownership of the object being passed in which means it assumes control over all memory management and will free it upon delete. From the setLayout docs:

The QWidget will take ownership of layout.

After you have called setLayout it has a parent and its parent deletes it in addition to it being deleted when the method's stack is cleaned up. Thus, it's being deleted twice which is causing the problems.

If everything else is correct, this change should fix it:

QVBoxLayout *layout = new QVBoxLayout();
//...
layout->addWidget(&testButton);
//...
editWindow.setLayout(layout);

Also, note that it's typical to create the main widget and then assign widgets that will be displayed on that widget as the parent. In other words, I'd expect something more like the following (though not strictly necessary). This also helps assure that if something does get reparented in the future you won't have problems:

QWidget editWindow;
QVBoxLayout *layout = new QVBoxLayout();
QPushButton *testButton = new QPushButton(&editWindow);
layout->addWidget(testButton);
editWindow.setLayout(layout);
editWindow.show();
int val = app.exec();

Most Qt objects which are reparented and to which ownership changes may happen will have a constructor that accepts a QWidget* or QObject*.

落日海湾 2024-11-30 18:19:18

QWidget 期望通过运算符 new 创建一个布局实例,并获得该实例的所有权,当 QWidget 被销毁时调用删除它(请参阅文档)。因此,您需要的是这样的:

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

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

QWidget expects a layout instance created via operator new and takes ownership of the instance, calling delete on it when the QWidget is destroyed (see documentation). Hence what you need is something like this:

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

The same thing with ownership applies to your testButton.

-黛色若梦 2024-11-30 18:19:18

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

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

现在,要理解为什么诺基亚发布了如此糟糕的例子......

The example code seems to be wrong (oddly enough). The destructor of a QWidget calls delete on its layout. In your case, the QVBoxLayout instance has been created on the stack rather than the heap, so calling delete on that pointer is invalid is aborts the application.

Same goes for all children of a QObject. When a QObject gets deleted, it calls delete on all of its children, and if those children have been created on the stack, it will fail in the same way.

Now, to understand why Nokia posted such a bad example...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文