Почему это приложение QT завершает работу с сигналом SIGABRT? - PullRequest
2 голосов
/ 14 июля 2011

Я новичок в Qt. Поэтому я начал переопределять один из примеров начала работы: ссылка .

Однако я получаю сигнал SIGABRT при закрытии окон. Причина этого кроется в некоторой ошибке управления памятью.

Ниже вы найдете стек вызовов и соответствующий код. Строка editWindow.setLayout(&layout); вызывает ошибку. Удаляет ли класс макета виджеты при уничтожении, утверждая, что им принадлежит право собственности?

Какова причина этого поведения? И как это исправить?

С уважением.

информация
CallStack
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();

Ответы [ 3 ]

7 голосов
/ 14 июля 2011

Множество различных функций 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*.

2 голосов
/ 14 июля 2011

QWidget ожидает экземпляр макета, созданный с помощью оператора new, и становится владельцем экземпляра, вызывая delete на нем, когда QWidget уничтожен ( см. Документацию ).Следовательно, вам нужно что-то вроде этого:

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

То же самое с владельцем относится к вашей кнопке testButton.

1 голос
/ 14 июля 2011

Пример кода кажется неправильным (как ни странно). Деструктор QWidget вызывает delete своего макета. В вашем случае экземпляр QVBoxLayout был создан в стеке, а не в куче, поэтому вызов delete для этого указателя недопустим, отменяет приложение.

То же самое относится ко всем детям QObject. Когда QObject удаляется, он вызывает delete для всех своих дочерних элементов, и, если эти дочерние элементы были созданы в стеке, он завершится таким же образом.

Теперь, чтобы понять, почему Nokia опубликовала такой плохой пример ...

...