Russian Qt Forum

Qt => Общие вопросы => Тема начата: xk от Октябрь 19, 2007, 16:41



Название: Механизм parent'ов, деструкторов
Отправлено: xk от Октябрь 19, 2007, 16:41
OS: win-xp
Qt: 4.3.2

Простая до тошноты программа вываливается при закрытии окна. Причем вываливается, судя по дебаггеру где-то внутри QToolBar. Сдается мне что я чего-то не понимаю в сабжевом механизме.
Подскажите что может быть не так ? может на другой платформе/версии Qt всё нормально ?

main.cpp
Код:
#include "app.h"

int main(int argc, char **argv)
{
  CApp app(argc, argv);
  return app.run();
}

app.h
Код:
#ifndef __GRADARAPP_H__
#define __GRADARAPP_H__

#include <QApplication>
#include "guimanager.h"

class CApp : public QApplication
{
public:
  CApp(int argc, char** argv);
  ~CApp();
  int run();

private:
  CGuiManager* m_pGuiManager;
};

#endif  // __GRADARAPP_H__

app.cpp
Код:
#include "app.h"

CApp::CApp(int argc, char** argv)
: QApplication(argc, argv)
{
  m_pGuiManager = new CGuiManager(this);
}

CApp::~CApp()
{
}

int CApp::run()
{
  return exec();
}

guimanager.h
Код:
#include <QObject>
#include "mainwin.h"

class CGuiManager : public QObject
{
public:
  CGuiManager(QObject* parent);
  ~CGuiManager();

private:
  CMainWindow* m_pMainWindow;
};

guimanager.cpp
Код:
#include "guimanager.h"

CGuiManager::CGuiManager(QObject* parent)
: QObject(parent)
{
  m_pMainWindow = new CMainWindow;
}

CGuiManager::~CGuiManager()
{
  delete m_pMainWindow;
}

mainwin.h
Код:
#ifndef __MAINWIN_H__
#define __MAINWIN_H__

#include <QMenu>
#include <QAction>
#include <QToolBar>
#include <QMainWindow>

class CMainWindow : public QMainWindow
{
public:
  CMainWindow();
  ~CMainWindow();

private:
  void createActions();
  void createMenus();
  void createToolBars();
  void createStatusBar();
 
private:
  QAction*  m_pExitAct;
  QMenu*    m_pFileMenu;
  QToolBar* m_pFileToolBar;
};

#endif  // __MAINWIN_H__

mainwin.cpp
Код:
#include <QTextEdit>
#include <QMenuBar>

#include "mainwin.h"

CMainWindow::CMainWindow()
{
  createActions();
  createMenus();
  createToolBars();
 
  QTextEdit* edit = new QTextEdit(this);
  setCentralWidget(edit);
 
  show();
}

CMainWindow::~CMainWindow()
{
}

void CMainWindow::createActions()
{
  m_pExitAct = new QAction(tr("E&xit"), this);
  connect(m_pExitAct, SIGNAL(triggered()), this, SLOT(close()));
  return;
}

void CMainWindow::createMenus()
{
  m_pFileMenu = menuBar()->addMenu(tr("&File"));
  m_pFileMenu->addAction(m_pExitAct);

  return;
}

void CMainWindow::createToolBars()
{
  m_pFileToolBar = addToolBar(tr("File"));
  m_pFileToolBar->addAction(m_pExitAct);

  return;
}


Название: Re: Механизм parent'ов, деструкторов
Отправлено: Kainit от Октябрь 19, 2007, 17:36
так должно писать уважающему себя мужу (если конечно не хочется ликов и ошибок)

Код:
CApp::~CApp()
{
delete m_pGuiManager;
}

Надеюсь, причина ошибки понятна...


Название: Re: Механизм parent'ов, деструкторов
Отправлено: xk от Октябрь 19, 2007, 17:51
Вот как раз не понятна  :)
Я ведь пишу
Код:
m_pGuiManager = new CGuiManager(this);
т.е. задаю parent'а, т.е. деструктор m_pGuiManager должен автоматически вызываться в деструкторе parent'a, коим является CApp app.


Название: Re: Механизм parent'ов, деструкторов
Отправлено: EhTemka от Октябрь 19, 2007, 18:15
Или я что-то недогоняю...

А как вообще у тебя происходит выход из процесса?

exec(); вижу, а где quit(), или что-то в этом роде?



Название: Re: Механизм parent'ов, деструкторов
Отправлено: Kainit от Октябрь 19, 2007, 18:20
Цитировать
exec(); вижу, а где quit(), или что-то в этом роде?
Какой quit(), окститесь и поглядите самый первый пример Qt.
Код:
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QPushButton hello("Hello world!");
    hello.resize(100, 30);

    hello.show();
    return app.exec();
}
У товарища всё написано правильно.

2xk
Предлагаю поставить брекпоинты и убедиться что все деструкторы вызываются вне зависимости от того, есть ли вставка
Код:
delete m_pGuiManager
или нету.

Разумеется, у QObject с наследованием и уничтожением потомков всё в порядке.

А в чём причина неадекватного поведения? Точно сказать сложно, но причина именно в последовательности удаления и в том что в Qt по разному в двух случаях освобождает ресурсы связанные с MainWindow и с Application.

А ошибка сама по себе забавная и я вижу такую впервые, поскольку всегда за собой удалял всё сам...


Название: Re: Механизм parent'ов, деструкторов
Отправлено: xk от Октябрь 19, 2007, 20:31
В обоих случаях деструкторы вызываются в нужном порядке.. только в варианте "new CGuiManager(this)", вылетает ошибка доступа к памяти.
Попробую троллям сейчас отослать...


Название: Re: Механизм parent'ов, деструкторов
Отправлено: Kainit от Октябрь 19, 2007, 21:35
Ты не понял мысли, хотя троллям ты отослать конечно можешь.

Я говорю не о порядке деструцирования твоих объектов app->pGuiManager->pMainWindow, я говорю о порядке деструцирования объектов данного приложения вообще. Если ты почитаешь исходники, или потыкаешь в проперти разных объектов (типа app, а точнее, в его список детей), то всё станет понятнее.

Когда ты явно говоришь delete pGuiManager, то сначала разрушается pGuiManager и pMainWindow, а затем уже разрушаются вспомогательные объекты, созданные QApplication  и потому всё завершается корректно.

Когда же ты не вызываешь delete pGuiManager, то дети QApplication  умирают в порядке создания, т.е., сначала всевозможные шрифтовые фабрики и т.п., а потом уже твои pGuiManager и pMainWindow (создал ты их позже и в список child-ов они попали в конец). Но по каким-то причинам, QMainWindow не знает о том что по сути весь контекст QApplication разрушился и твоя прога падает.

Цитировать
Попробую троллям сейчас отослать...
Тролли посмеются.


Название: Re: Механизм parent'ов, деструкторов
Отправлено: Dodge от Октябрь 20, 2007, 01:20
Ужос... зачем наследоватццо от QApplication? о_0

Что вам простите там понадобилось, это не Qt'шный стиль! ...и вообще... лучше избежать наследования, если это возможно. Но и не это главное... QApplication этж синглтон - ядро вашей программы, сингл тон в полном порядке и багов за ним не значитццо... тк зачем к нему своито прекручивать... жжжесть...

З.Ы. Аффтор, если не ошибаюсь, сам Страуструп( можт это был и Архангельской... ну не суть ) грозил пальчиком и говорил: ай-ай-ай... незя наследоватся без нужды... ай-ай-ай  ;D
Многие опытные программисты рекомендуют применять наследование в случаех с интерфейсом... неговоря уже а множественном наследовании...

Ну это все лирика... к чему это все - ОСТАВЬ В ПОКОЕ QApplication! У него хоть диструктор и виртуальный... но лучше его не трогать. Посмотри как пишут сами троли. Загляни в экзамплы... я думаю проблемма исчезнет.


Название: Re: Механизм parent'ов, деструкторов
Отправлено: xk от Октябрь 20, 2007, 08:45
Да, с наследованием от QApplication - это я погорячился :)
Проблема решена, всем спасибо !  :)


Название: Re: Механизм parent'ов, деструкторов
Отправлено: Cyrax от Декабрь 19, 2007, 15:17
По поводу деструкторов и parent'ов:  не закрывается дочернее окно при закрытии главного.
Имеется главное окно dep и дочернее tload, оба - наследники QMainWindow.
Из главного окна создаю и отображаю дочернее окно:
Цитировать
tload = new tgLoad(this);
tload->show();
Запускаю приложение, из главного окна открываю дочернее tload. Затем закрываю главное. При этом дочернее окно не закрывается, хотя в конструкторе tload'а в качестве родителя я указываю this, т.е. объект главного окна.

Далее dDebug'ами проверяю последовательность вызова конструкторов и деструкторов.
Получаю следующие результаты:
1. Открываю dep, открываю tload, закрываю tload, закрываю dep:
Цитировать
warning: dep constructor
warning: tload constructor
warning: dep destructor
warning: tload destructor
Последние 2 сообщения выводятся только при закрытии главного окна dep. Т.е. деструктор tload вызывается не при закрытии окна tload, а только при закрытии главного окна dep.
Как по мне, должно быть так:
Цитировать
warning: dep constructor
warning: tload constructor
warning: tload destructor
warning: dep destructor
2. Открываю dep, открываю tload, закрываю dep:
Цитировать
warning: dep constructor
warning: tload constructor
warning: dep destructor
warning: tload destructor
Та же самая последовательность вызовов, при этом при закрытии главного окна дочернее не закрывается.
В данном случае должно быть так:
Цитировать
warning: dep constructor
warning: tload constructor
warning: tload destructor
warning: dep destructor

Если недопонимаю чего-то простого, просьба не РРРРРычать...


Название: Re: Механизм parent'ов, деструкторов
Отправлено: _govorilka от Декабрь 19, 2007, 15:46
Сделай вот так, и попробуй запустить...
Код:
CGuiManager::~CGuiManager()
{
  //delete m_pMainWindow;
}

В твоём случае, окно должно удалиться самостоятельно (это написано внутри библиотеки).

Если хочешь удалять окна ручками, то надо писать вот так:

Код:
m_mуWindow->deleteLater();
m_mуWindow = 0;


Название: Re: Механизм parent'ов, деструкторов
Отправлено: Вячеслав от Декабрь 19, 2007, 16:34
Вообще-то RTFM ;) При закрытии окно не удаляеться по-умолчанию,а скрываеться и прибиваеться парентом ;) Ставь флаг однако ....

setAttribute(Qt::WA_DeleteOnClose);


Название: Re: Механизм parent'ов, деструкторов
Отправлено: ритт от Декабрь 19, 2007, 17:33
а мне вот всё-рно хочется поРРРРРычать...
неделю-две назад только закрыли эту тему, где всё развёрнуто было оговорено и расжёвано
уже 177 страниц форума - такие вопросы ну по-любому должны были проскакивать...но вот, лень же ж вам, люди, поиском-то воспользоваться?!


Название: Re: Механизм parent'ов, деструкторов
Отправлено: ритт от Декабрь 19, 2007, 18:04
а амароки отнаследовались от куаппликэйшена...чёрт...как я в них разочаровался
а ведь амарок был моим любимым плеером...теперь придётся выбросить!  :(


Название: Re: Механизм parent'ов, деструкторов
Отправлено: Cyrax от Декабрь 19, 2007, 19:55
Всё понятно, спасибо.

Цитировать
неделю-две назад только закрыли эту тему, где всё развёрнуто было оговорено и расжёвано
http://prog.org.ru/forum/index.php/topic,6541.0.html ?

Собственно, для того, чтобы при закрытии главного окна закрывались все дочерние и при этом не вываливалось ошибок, хотел вначале очистить свойство quitOnLastWindowClosed приложения (по умолчанию - установлено) + для главного окна установить свойство setAttribute(Qt::WA_DeleteOnClose, true) + законнектить "сигнал удаления главного" окна на слот quit() приложения. Поскольку у QMainWindow нет "сигнала удаления", придётся его генерировать вручную в деструкторе. Довольно муторно.
Пока остановился на варианте, когда свойство quitOnLastWindowClosed оставляю установленным + перегружаю слот closeEvent() в главном окне:
Цитировать
void dep::closeEvent(QCloseEvent *event)
{
    this->tload->close();
    QMainWindow::closeEvent(event);
}
В данном случае при закрытии главного окна вначале закрывается (hide'ится) дочернее окно (tload), затем - главное (dep). Далее срабатывает атрибут quitOnLastWindowClosed...

Поправте, если что не так.


Название: Re: Механизм parent'ов, деструкторов
Отправлено: ритт от Декабрь 19, 2007, 20:30
> Поскольку у QMainWindow нет "сигнала удаления"...
QMainWindow не наследуется от QObect??? я в шоке! всегда думал, что наследуется...

а что мешает ставить в конструкторе Qt::WA_DeleteOnClose, а в деструкторе делать клозе() дитёнку для надёжности?


Название: Re: Механизм parent'ов, деструкторов
Отправлено: Cyrax от Декабрь 19, 2007, 21:10
Цитировать
а что мешает ставить в конструкторе Qt::WA_DeleteOnClose, а в деструкторе делать клозе() дитёнку для надёжности?
Я так делал - вываливается runtime error (в режиме run).
В главном окне в конструкторе устанавливаю атрибут Qt::WA_DeleteOnClose. quitOnLastWindowClosed не трогаю. Запускаю приложение с главным окном (дочернее вообще не запускаю) и закрываю главное окно.
При этом вываливается ошибка (приложение остаётся в памяти):
Цитировать
warning: dep constructor
warning: dep destructor
warning: HEAP[dep.exe]:
warning: Invalid Address specified to RtlFreeHeap( 003E0000, 0022FD30 )
Previous frame inner to this frame (corrupt stack?)

При закрытии окна оно удаляется, согласно атрибуту Qt::WA_DeleteOnClose, удаляет детёнышей. Наверное срабатывает атрибут quitOnLastWindowClosed приложения, установленный по умолчанию, который пытается ещё раз удалить главное окно...


Название: Re: Механизм parent'ов, деструкторов
Отправлено: ритт от Декабрь 19, 2007, 21:33
считай, что у меня на лице тень смущения, но я все же спрошу:
в конструкторе ставишь дитёнку 0, а в деструкторе проверяешь дитёнка на не 0 перед попыткой закрыть?


Название: Re: Механизм parent'ов, деструкторов
Отправлено: pastor от Декабрь 19, 2007, 22:03
2 Cyrax: Покажи как создаешь гланое окно. Не в стеке случайно? Если да, то это не удивительно что будет падать при закрытии с флагом Qt::WA_DeleteOnClose :)


Название: Re: Механизм parent'ов, деструкторов
Отправлено: Cyrax от Декабрь 19, 2007, 22:57
Блин, в стеке ведь... удаляется дважды...
Это Qt Eclipse integration так проект заделал, я уж забыл про это совсем...

В данном случае идеологически корректным будет создание в стеке или в куче ?


Название: Re: Механизм parent'ов, деструкторов
Отправлено: pastor от Декабрь 19, 2007, 23:23
Блин, в стеке ведь... удаляется дважды...
Это Qt Eclipse integration так проект заделал, я уж забыл про это совсем...

В данном случае идеологически корректным будет создание в стеке или в куче ?

Если юзаеться Qt::WA_DeleteOnClose, то виджет должен быть создан в куче. Инече будет двойное удаление