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

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

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Вопрос про удаление QObject находящегося в иерархии  (Прочитано 9630 раз)
kamil
Гость
« : Май 03, 2015, 13:12 »

В программе возникла проблема, и я уверен, что многие с ней сталкивались.

Есть класс Plot отвечающий за отрисовку одного графика. Среди членов класса - указатели на QWidget (имя графика, цвет, и т. п.). Эти QWidget должны удаляться в двух местах:
- автоматически при выходе из программы, так как они в иерархии QObject являются потомками QMainWindow
- в ручную, когда удаляется сам экземпляр класса Plot, например когда нужно загрузить новые графики из другого файла, а старые удалить.

Если в деструкторе Plot написать:
Код:
delete pointerToWidget;
То при ручном удалении все сработает, но появится проблема при автоматическом удалении - к моменту вызова ~Plot pointerToWidget будет уже удалён, и на delete pointerToWidget; программа выпадет.
Если вместо ручного удаления просто скрывать pointerToWidget, чтобы он во время выхода сам удалился - по мере открывания файлов объекты будут скапливаться, забивая память.

Как обычно поступают в такой ситуации?
Записан
Bepec
Гость
« Ответ #1 : Май 03, 2015, 13:29 »

Вы сами контролируйте состояние.
Сделайте обнуление указателя и добавьте проверку при его удалении.

Код:
if (pointerToWidget)
{
    delete pointerToWidget;
    pointerToWidget = NULL; 
}

И да, не забудьте обнулить указатель в конструкторе, а то креш словите Улыбающийся
Записан
Old
Джедай : наставник для всех
*******
Online Online

Сообщений: 4350



Просмотр профиля
« Ответ #2 : Май 03, 2015, 13:35 »

Не нужна эта бесполезная проверка на 0, delete сам прекрасно это проверяет.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #3 : Май 03, 2015, 13:49 »

Как обычно поступают в такой ситуации?
Используют QPointer
Записан
kamil
Гость
« Ответ #4 : Май 03, 2015, 17:18 »

Bepec, спасибо, убрал виджеты из иерархии и удаляю вручную - всё нормально.
Old, да, проверка не нужна, delete нормально есть NULL
Igors, тут вроде как и без QPointer можно обойтись - практически как и в любой другой ситуации...

Update:
Bepec, ничего не нормально. При попытке убрать виджет из иерархии (setParent(NULL)), все виджеты оказываются в отдельных окнах (странно, я думал иерархия QObject и иерархия в ui это разные вещи). Как ещё можно самому контролировать время жизни виджетов?
« Последнее редактирование: Май 03, 2015, 17:39 от kamil » Записан
Old
Джедай : наставник для всех
*******
Online Online

Сообщений: 4350



Просмотр профиля
« Ответ #5 : Май 03, 2015, 19:28 »

Проверьте ещё раз, если вы виджет удаляете руками, например, в деструктор, то он автоматически вычеркивается из списка своего parent и не будет удаляться автоматически, при разрушении parent.
Записан
lit-uriy
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3880


Просмотр профиля WWW
« Ответ #6 : Май 03, 2015, 20:04 »

Наследников QObject нужно удалять через их метод deleteLater()
Записан

Юра.
Bepec
Гость
« Ответ #7 : Май 03, 2015, 20:58 »

Нуууу, тут непонятно что у вас творится.

Тут надо выбрать один подход - или вы держитесь за систему Qt, или вы сами управляете объектами.

PS выход подсказывает lit-uriy Улыбающийся
Записан
kamil
Гость
« Ответ #8 : Май 03, 2015, 23:23 »

Bepec, как мне вручную контролировать время жизни объектов, которые являются частью иерархии QMainWindow?

lit-uriy, deleteLater() я использовать не могу - я уже говорил что к тому моменту как вызывается деструктор класса Plot, объект может быть удалён уже самим qt. Я не знаю как можно проверить удалён объект или нет, не используя QPointer.

Old, вы правы, если я удалил объект первым, то через иерархию QMainWindow он не станет удаляться. А если первым удалит сам Qt?

Попробую объяснить ситуацию ещё раз. Деструкор некоторого объекта вызывается в двух случаях:
 - во время работы программы. В этом случае нужно удалить некоторый QWidget вручную.
 - когда закрывается программа. В этом случае QWidget уже может быть удалён самим Qt как потомок в иерархии QMainWindow.

Действительно, как говорил Верес, нужно, например, управлять временем жизнью QObject самостоятельно. Как это сделать я не знаю.
Либо же оставить право Qt удалять объекты, но проверять, не удалён ли уже объект, прежде чем вызывать delete. Как это сделать я тоже не знаю.
В голову пока приходит только QPointer.
Записан
Old
Джедай : наставник для всех
*******
Online Online

Сообщений: 4350



Просмотр профиля
« Ответ #9 : Май 04, 2015, 02:07 »

Дочернии объекты удаляются только при удалении родительского объекта. Т.е. в вашем случае, при удалении главного окно. Как правило это происходит в функции main при завершении программы. До этого момента, Qt не сможет ничего удалить, поэтому смело удаляйте нужные объекты руками, там где это нужно.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #10 : Май 04, 2015, 09:01 »

Igors, тут вроде как и без QPointer можно обойтись - практически как и в любой другой ситуации...
Можно, но зачем? Не вижу какие минусы имеет это решение, тем более оно штатное. Может что-то "оптимизировать" собрались?  Улыбающийся
Записан
Bepec
Гость
« Ответ #11 : Май 04, 2015, 11:50 »

to Old:
Проверка на NULL нужна не для delete, а для пользователя. Он вполне бы не инициализировал нуллом в конструкторе и поймал непонятный креш. Лишь дополнительный контроль за собой, хотя самоуверенные и люди с опытом, могут не пользоваться Веселый
Записан
Old
Джедай : наставник для всех
*******
Online Online

Сообщений: 4350



Просмотр профиля
« Ответ #12 : Май 04, 2015, 12:22 »

to Old:
Проверка на NULL нужна не для delete, а для пользователя. Он вполне бы не инициализировал нуллом в конструкторе и поймал непонятный креш. Лишь дополнительный контроль за собой, хотя самоуверенные и люди с опытом, могут не пользоваться Веселый
Если пользователь не инициализирует указатель в конструкторе, он словит тотже краш. Эта проверка ему ничем не поможет.
Записан
Bepec
Гость
« Ответ #13 : Май 04, 2015, 21:00 »

Эта проверка поможет тем, что на ней проверка на Null явная и её можно пошагово разобрать.
И понять, что указатель не равен NULL, а не "что то произошло внутри delete, а вот что - хрен разбрёшь" Улыбающийся

Собственно это для удобства программиста и отладки. Акцентирую - отладки, а не для написания совершенного кода Веселый
Записан
Old
Джедай : наставник для всех
*******
Online Online

Сообщений: 4350



Просмотр профиля
« Ответ #14 : Май 04, 2015, 21:08 »

Тогда лучше так:
Код
C++ (Qt)
if( ptr )
{
   if(ptr )
   {
       delete ptr;
       ptr = 0;
   }
   ptr = 0;
}
 
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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