Russian Qt Forum
Октябрь 01, 2024, 02:31 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: [Qt4] QTabWidget - кооректная чистка памяти  (Прочитано 17513 раз)
Unnamed_Hero
Гость
« : Июнь 23, 2008, 13:04 »

Пытаюсь понять, как корректно работать с tabWidget'ом.
Есть у меня нарисованный в дизайнере виджет. В классе, его описывающем, ещё присутствует некоторое количество вычислений, ради чего внутри класса создаются объекты пары других классов.

По нажатию кнопки в главной программе - создаётся новый объект этого виджета и добавляется на новую вкладку tabWidget'a. 

По нажатию другой кнопки - надо грохнуть текущий виджет из текущей вкладки  (и саму вкладку) и удалить из памяти всё то, что он насоздавал.

Как это сделать наиболее корректно? В моей реализации у меня гигантские утечки памяти Грустный
Записан
lit-uriy
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3880


Просмотр профиля WWW
« Ответ #1 : Июнь 23, 2008, 13:28 »

покажи как сам делаешь
Записан

Юра.
lit-uriy
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3880


Просмотр профиля WWW
« Ответ #2 : Июнь 23, 2008, 13:33 »

чтоб добавить виджет, делай так:
tab->addTab(new MyWidget(this), tr("Вкладка №1"));
чтобы удалить текущую вкладку, делай так
tab->removeTab( currentIndex ());
Записан

Юра.
Unnamed_Hero
Гость
« Ответ #3 : Июнь 23, 2008, 14:50 »

Сделал по написанному. Тоже самое.
Но если верить Assistant'у

Цитата: QT Assistant
void QTabWidget::removeTab ( int index )
Removes the tab at position index from this stack of widgets. The page widget itself is not deleted

Да если верить valdrind'у - объекты классов, которые создаются в конструкторе виджета - не удаляются Грустный
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #4 : Июнь 23, 2008, 16:59 »

А что мешает самому удалить свой виджет?
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
Unnamed_Hero
Гость
« Ответ #5 : Июнь 23, 2008, 21:57 »

А как корректно удалять его?

Мне даже не сколько сам виджет грохнуть надо, сколько подчистить за ним  - там создаётся несколько указателей на объекты, и они не удаляются, хотя удаление всех объектов прописал в деструкторе.

Наверное, будет проще выложить сюда кусок кода, чтобы было более наглядно. Только предупреждаю сразу - я начинающий, и поэтому код может быть ужасен Улыбающийся


tabWidget->addTab (new char_Sheet (&someData,"sometabname"));

в конструкторе char_Sheet
создаются объекты других классов для проведения вычислений и преобразований.
В деструкторе класса все объявленные объекты delete'аются....
Когда я просто делаю removeTab, то память не освобождается.
Если создать массив указателей char_sheet *charArray[];
и говорить delete нужному номеру, то это освобождает часть памяти (удаляется сам виджет, а порождённые им объекты - висят в памяти.) Может, стоит всем классам вычислений ещё прописывать родителя, который их рождает, чтобы они вместе с ним удалялись?

Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #6 : Июнь 23, 2008, 22:00 »

Да, нужно указывать родителя, который и поубивает всех детей при разрушении. :-D
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
Alex03
Гость
« Ответ #7 : Июнь 24, 2008, 05:44 »

чтоб добавить виджет, делай так:
tab->addTab(new MyWidget(this), tr("Вкладка №1"));
чтобы удалить текущую вкладку, делай так
tab->removeTab( currentIndex ());
Вы б определились что у Вас не удаляется, если сама закладка то:
Код:
    QWidget * pw = widget(currentIndex ());
    tab->removeTab( currentIndex ());
    delete pw;

Записан
Red Devil
Гость
« Ответ #8 : Июнь 28, 2008, 23:23 »

Хочу обратить внимание на то, что в QWidget не виртуальный деструктор.
Поэтому перед удалением, необходимо преобразовать указатель к тому обьекту для которого была выделена память изначально, иначе будут утечки памяти.
Неправильно :
Код:
m_pTab->addWidget(new QTextEdit, "New file");
...
QWidget * pWidget = m_pTab->currentWidget();
m_pTab->removeTab( currentIndex () );
delete pWidget;

Правильно :
Код:
m_pTab->addWidget(new QTextEdit, "New file");
...
QTextEdit * pEdit = static_cast<QTextEdit*>(m_pTab->currentWidget());
m_pTab->removeTab( currentIndex () );
delete pEdit;
« Последнее редактирование: Июнь 28, 2008, 23:30 от Red Devil » Записан
Sergeich
Гость
« Ответ #9 : Июнь 29, 2008, 00:07 »

Хочу обратить внимание на то, что в QWidget не виртуальный деструктор.
С чего ты взял что он не виртуальный? У QObject - виртуальный деструктор - следовательно он виртуальный у всех его потомков, с том числе и QWidget.
Записан
Red Devil
Гость
« Ответ #10 : Июнь 29, 2008, 00:20 »

Да точно. Я забыл про QObject. Проверил и убедился, все правильно удаляется.

Но кстати вот еще проблема появилась. При удалении обьекта, в трейсе видно сообщение :
QObject: Do not delete object, 'unnamed', during its event handler!

Вот я где-то (на страничку эту уже не зайти, я её открыл с помощью кеша гугла) нашел обсуждение по его поводу.
Цитировать
Неоднократно замечены проблемы с перекрытием в обработке событий/сигналов
и
удаления объекта с этими обработчиками.

На QT4.4 он начал предупреждать о подобном:
QObject: Do not delete object, 'unnamed', during its event handler!

Но не понятно другое, как это возможно в одном потоке и как это разруливать?
Ситуация достаточно неочевидна и перестройкой пользовательского кода
часто не
лечится или лечится только путём потери функциональности.

Например ситуация:
- инспектор атрибутов генерирует сигнал на обновления виджета при потере
фокуса; в процессе обновления удаляется вложенный виджет и вместо него
создаётся новый;
- в тоже время фокус теряется по причине выбора этого самого виджета
(удаляемого), т.е. какие-то события пошли к нему;
- в результате генерируется "QObject: Do not delete object, 'unnamed', during
its event handler!" и происходит обрушение.

Я не понимаю как такое может вообще происходить, разве в деструкторе не
откидываются из очереди события к удаляемому виджету?

Порылся в коде QT4.4 и меня насторожил вот этот участок кода в функции
QCoreApplication::notifyInternal( ) файла qcoreapplication.cpp:
    bool returnValue;
    try {
        returnValue = notify(receiver, event);
    } catch(...) {
        --threadData->loopLevel;
        throw;
    }
Получается при возникновении исключения оно передаётся на уровень выше, а
флаг
d->inEventHandler не очищается, что и является причиной указанного сообщения, а
установка этого флага осуществляется только там. Не исключено, что не
очищается
ещё чего нибуть.

------- Comment #1 From Roman Savochenko 2008-05-26 21:45:26 -------

Created an attachment (id=2645) [details]
Программа демонстрации проблемы

Подготовил наглядный пример этой проблемы на основе примера из дистрибутива
QT4.4 - basiclayouts. Для кнопки Button1 добавил eventFilter() c целью отлова
потери фокуса. По результату потери фокуса удаляется кнопка Button2. Так вот,
если сначала нажать кнопку Button1, а затем Button3, то кнопка Button2
корректно удалится, а вот если после Button1 нажать Button2, то программа
упадёт по этой самой проблеме.

------- Comment #2 From Michael Shigorin 2008-05-31 02:43:48 -------

alterator-browser-qt - X11 Qt interface driver for alterator           
* Fri May 30 2008 Sergey V Turchin <zerg@altlinux> 2.9.83-alt1                 
                   
- fix #15792
* Fri May 30 2008 Sergey V Turchin <zerg@altlinux> 2.9.82-alt1
- fix *listbox state-rows attribute 
- force return *multi*listbox current-rows and state-rows if empty list
* Thu May 29 2008 Sergey V Turchin <zerg@altlinux> 2.9.81-alt1

------- Comment #3 From Sergey V Turchin 2008-06-02 17:26:37 -------

Я не уверен, это бага Qt или нет, но можно использовать deleteLater

------- Comment #4 From Roman Savochenko 2008-06-02 17:56:29 -------

Это не всегда возможно.
У меня был случай с QAbstractItemView::itemDelegate()
Когда я создаю в качестве элемента редактирования комбобокс(редактируемый) и
добавляю ему обработку события принятия выбора по выбору элемента.
Так вот, если я редактирую содержимое этого комбобокса руками и нажимаю Enter,
то приходит два события и он валится поскольку сама QT удалила этот элемент
после первого события.

Кроме того, на динамических интерфейсах, где элементы часто создаются и
удаляются это неизбежно будет и проблему просто так не обойдёшь.

------- Comment #5 From Sergey V Turchin 2008-06-10 17:27:30 -------

Похоже, в Trolltech думают, что это фича
http://trolltech.net/developer/task-tracker/index_html?method=entry&id=198093
http://trolltech.de/developer/task-tracker/index_html?method=entry&id=205903

------- Comment #6 From Roman Savochenko 2008-06-24 00:14:37 -------

Если бы оно только писало и не падало.
В приложенном примере нет моего кода, а оно устойчиво падает на банальной
ситуации.
« Последнее редактирование: Июнь 29, 2008, 00:23 от Red Devil » Записан
Sergeich
Гость
« Ответ #11 : Июнь 29, 2008, 00:33 »

Юзай QObject::deleteLater ()
Записан
Unnamed_Hero
Гость
« Ответ #12 : Июнь 29, 2008, 10:51 »

Не знаю, насколько это корректно.... но я пока что поступаю таким образом -
Код:
int index = tabWidget->currentIndex();
QWidget* deadwidget =tabWidget-> widget(index);
deadwidget->close();
в конструкторе виджета для вкладки tabWidget
Код:
setAttribute(Qt::WA_DeleteOnClose);

всё удаляется... вроде Улыбающийся
Во всяком случае - видно, что деструкторы вызываются для всех объектов.
Записан
Red Devil
Гость
« Ответ #13 : Июнь 29, 2008, 12:02 »

Юзай QObject::deleteLater ()
Т.е. сам Qt удалит обьект, после того отработает цикл сообщений для него. И самому вручную delete использоваться получается не нужно.
Но вот хотелось бы удостоверится что это действительно так.
Записан
Sergeich
Гость
« Ответ #14 : Июнь 29, 2008, 13:44 »

Юзай QObject::deleteLater ()
Т.е. сам Qt удалит обьект, после того отработает цикл сообщений для него. И самому вручную delete использоваться получается не нужно.
Но вот хотелось бы удостоверится что это действительно так.
Да, именно так.
Код:
void QObject::deleteLater()
{
    QCoreApplication::postEvent(this, new QEvent(QEvent::DeferredDelete));
}
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.123 секунд. Запросов: 23.