Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > С/С++: Кроссплатформенное программирование, Qt/Gtk+/wxWidgets > Удаление QObject: автоматически или нет


Автор: sustenuto 29.5.2011, 19:26
Здравствуйте! Я первый раз работаю с QT и столкнулся с проблемой, решение которой не смог найти в документации. Суть сводиться к тому, что не ясно, кто должен удалять объект, производный от QObject: я или библиотека QT. Оказывается, что оба случая работают неправильно: если я создаю объект как статическую переменную (которая удаляется автоматически во время завершения программы), либо если я создаю его динамически, оператором new, и не удаляю совсем. В первом случае я получаю Segmentation Fault, во втором — утечку памяти. 

Мой класс описан примерно вот так:

Код

class LoadFileDialog : public QDialog , public Ui::LoadFileDialog {
    Q_OBJECT
public:
    LoadFileDialog(QWidget* parent=NULL);

    static bool showLoadFileWindow(const std::string& filename);

    void closeEvent (QCloseEvent * e);
private slots:
    void on_LoadFileButtons_clicked(QAbstractButton *);
    void update_data();
private:

    void paintEvent(QPaintEvent *event);
    void showFrame(Frame*);

public:
   ~LoadFileDialog() {
       std::cout<<"DIALOG DESTROYED!!!!"<<std::endl;
    }
};


Если объект LoadFileDialog сделать статической переменной, то при работе во время вызова его деструктора происходит Segmentation Fault. Если я объект не удаляю, то деструктор не вызывается вообще! Это я вижу, поскольку надписи "DIALOG DESTROYED!!!!" нет. Я предположил, что объект всё-таки уничтожается, но в силу того, что деструкторы QDialog и QWidget НЕ ВИРТУАЛЬНЫ (в отличие от деструктора QObject), вызывается неправильный деструктор. 

Друзья, как правильно делать?

PS. Кстати, если у меня ещё что-нибудь неправильно в классе, скажите плиз. Буду благодарен)

Автор: borisbn 29.5.2011, 19:31
Цитата(sustenuto @  29.5.2011,  19:26 Найти цитируемый пост)
деструкторы QDialog и QWidget НЕ ВИРТУАЛЬНЫ (в отличие от деструктора QObject)

на самом деле они виртуальные, т.к. при наследовании от QObject, где, как ты и сказал, деструктор виртуальный, их деструкторы (также, как и твой) становятся виртуальными.

где именно ты создаёшь объект LoadFileDialog статически, и где динамически ? Выложи весь код ( не жалей винград  smile ). А то так не очень понятно

Автор: sustenuto 29.5.2011, 19:42
borisbn, спасибо за ответ!

Цитата(borisbn @  29.5.2011,  19:31 Найти цитируемый пост)
на самом деле они виртуальные, т.к. при наследовании от QObject, где, как ты и сказал, деструктор виртуальный, их деструкторы (также, как и твой) становятся виртуальными.


На самом деле, не совсем так. То есть если вызывается `delete dialog' где dialog имеет тип QDialog* (и фактически является объектом LoadFileDialog), то вызовется ~QDialog(). При этом `delete (QObject*)dialog' вызовет ~LoadFileDialog(). Я так понимаю.

Цитата(borisbn @  29.5.2011,  19:31 Найти цитируемый пост)
где именно ты создаёшь объект LoadFileDialog статически, и где динамически


Вроде бы максимально упростил код, ошибка сохраняется:

1. Статически. После закрытия окна получаю Segmentation Fault
Код

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    static LoadFileDialog dlg;
    dlg.show();

    return app.exec();
}


2. Динамически. Деструктор ~LoadFileDialog() никогда не вызывается
Код

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    LoadFileDialog* dlg=new LoadFileDialog;
    dlg->show();

    return app.exec();;
}


Автор: kosmonaFFFt 30.5.2011, 05:40
А попробуй создавать не статически, а просто
Код

LoadFileDialog dlg;


Автор: math64 30.5.2011, 07:42
Когда ты создаёшь переменную так:
Код

    static LoadFileDialog dlg;

вместе с переменной dlg создаётся булевская переменная, по которой проверяется, создавался ли объект dlg. При первом вызове main() он будет создан.
Деструктор dlg будет вызван перед завершением программы, т.е. после выхода из main(), перед которым был вызван деструктор app, что и вызывает ошибку.
Нужно объявлять так:
Код

    QApplication app(argc, argv);
    LoadFileDialog dlg;

В этом случае деструкторы будут вызывааться при выходе из main() в порядке, обратном объявлению.

Автор: sustenuto 30.5.2011, 14:03
Цитата(kosmonaFFFt @  30.5.2011,  05:40 Найти цитируемый пост)
А попробуй создавать не статически, а просто


Цитата(math64 @  30.5.2011,  07:42 Найти цитируемый пост)
Нужно объявлять так:


Ага, спасибо!
Только проблема в том, что объект надо создавать не в main, а в другой функции.
Можно было бы делать QApplication app статическим, но у него нету конструктора по умолчанию((( Так что и этот вариант тоже не прокатывает(

Решение проблемы я нашёл:
создавать dialog динамически и затем выполнять 
Код

dialog.setAttribute(Qt::WA_DeleteOnClose, true);

Тогда он удаляется корректно.

Всем спасибо!

Автор: math64 30.5.2011, 14:35
Цитата(sustenuto @  30.5.2011,  14:03 Найти цитируемый пост)
Только проблема в том, что объект надо создавать не в main, а в другой функции.
Можно было бы делать QApplication app статическим, но у него нету конструктора по умолчанию((( Так что и этот вариант тоже не прокатывает(

Создай класс, производный от QApplication и сделай LoadFileDialog dlg; или LoadFileDialog* dlg; полем в этом классе.

Автор: sustenuto 2.6.2011, 18:20
Цитата(math64 @  30.5.2011,  14:35 Найти цитируемый пост)
Создай класс, производный от QApplication и сделай LoadFileDialog dlg; или LoadFileDialog* dlg; полем в этом классе. 


Здорово, отличное и красивое решение! Спасибо

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)