Удаление экземпляра класса stati c типа QWidget приводит к ошибке неверного указателя - PullRequest
0 голосов
/ 14 января 2020

Я пытался создать одноэлементный класс, создав подкласс QWidget и экспортировав экземпляр класса stati c. Однако попытка удалить такой экземпляр приводит к взлому sh. Почему?

#include <QWidget>
#include <QApplication>

using namespace std;

class MyWidget : public QWidget
{
  public:
    static MyWidget *get_instance(){ static MyWidget instance; return &instance; };
};



int main
(
  int argc,
  char **argv
)
{
    QApplication app( argc, argv );
    MyWidget *widget = MyWidget::get_instance();

    QWidget *parent_widget = new QWidget;
    widget->setParent( parent_widget );
    delete parent_widget; //crashes 

    return app.exec();
}

Запуск приведенного выше кода приводит к появлению следующих сообщений об ошибках. Я не включил сообщение bakctrace, которое слишком длинное, чтобы его можно было отобразить в этом сообщении.

QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/tmp/runtime-jon'
QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/tmp/runtime-jon'
*** Error in `/home/shouheng/tmp/build-exp_main-Desktop_Qt_5_10_0_GCC_64bit-Debug/exp_main': free(): invalid pointer: 0x00000000006030c0 ***

Ответы [ 2 ]

3 голосов
/ 14 января 2020

Когда вы удаляете родительский виджет, delete будет вызываться для всех его дочерних элементов, то есть для указателя на ваш одноэлементный объект, который не был создан с помощью new, т.е. не размещен в куче:

static MyWidget instance; 

Чтобы избежать этого, просто un-parent одиночный объект, таким образом

widget->setParent(nullptr);

перед вызовом delete на parent_widget.

2 голосов
/ 14 января 2020

Qt передает / обрабатывает владение вместе с родителем.

Поэтому, когда вы выполните

widget->setParent( parent_widget );

parent_widget, удалите widget в своем деструкторе (кроме случаев, когда его родители изменились ранее).

...