| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > С/С++: Кроссплатформенное программирование, Qt/Gtk+/wxWidgets > Время жизни объекта |
| Автор: xbarmaglot 12.9.2012, 10:53 | ||||||
| Есть объект, который реализует всю возложенную на него логику. Ее хотелось побить на части. Для этого я возвращаю вспомогательные объекты, которые решают узкую часть задач.
Ну или объект Some имеет открытый конструктор и используется так.
Если бы Some не использовался снаружи, то имел бы время жизни не более чем время жизни Parent. Тогда при удалении Parent разрушен был бы и Some. Но что будет если
Будет ли хотябы отладочное разумное сообщение или просто вылет приложения? Не отдавать же классу Some в конструкторе QSharedPointer на Parent. Ведь в документации обычно не пишут про время жизни вспомогательных объектов. По крайнем мере я в документации QT это не встречал. |
| Автор: Amp 12.9.2012, 13:04 |
| Вылет. В документации они дают вполне разумные рекомендации "We do not recommend holding pointers to child objects from outside the parent". Можно также подписаться на сигнал destroyed(). |
| Автор: borisbn 12.9.2012, 13:11 |
почему ? |
| Автор: xbarmaglot 12.9.2012, 13:30 | ||
так я его держу
|
| Автор: Amp 12.9.2012, 13:31 | ||||
Обычно QFile создается либо на стэке, либо является приватным членом класса. При таких раскладах его сложно случайно испортить или удалить. Но вообще надо следить и стараться выстраивать логику приложения, чтобы максимально обезопасить себя от таких ситуаций. И вне Qt можно с легкостью остаться с невалидным указателем на руках.
Сигнал получает тот объект, к которому он присоединен. Если речь о том объекте, который послал сигнал - то он после сигнала будет уничтожен. Это уведомление. |
| Автор: math64 12.9.2012, 13:49 | ||
Организуйте класс так:
При удалении связанного объекта, Some::Private получит сигнал, прочистит поле p в родительском Some и удалится. Some при вызове методов проверяет поле p на NULL- напрямую к методам Some::Private обратиться нельзя. |
| Автор: xbarmaglot 12.9.2012, 13:53 | ||
| math64, я как раз от этого хотел и уйти. У меня объект имеет доступ с несколький десяткам интерфейсов (нак исторически сложилось Я хотел не вызывать их в одном класе
А поделить их с помощью классов оберток. Тогда можно было бы раздавать их по необходимости. А не всю кучу, чтоб кто-нибудь случайно что-то не дернул |
| Автор: math64 12.9.2012, 14:51 | ||
| А кто мешает добавить в мой код ещё оберток - сколько тебе нужно. Идея - сам объект сидит во внутреннем private классе, его даже не обязательно объявлять в заколовке и раскрывать пользователю твоего API его структуру. А обётрок на него можешь наплодить сколько хочешь.
При этом нужно не забывать определить копирующий конструктор и оператор присваивания и увеличивать там счётчик. Для работы со счётчиком в Qt есть специальный класс, с ...Atomic... в названии |
| Автор: xbarmaglot 12.9.2012, 14:58 |
| math64, а чем твой код отличается от моего ? |
| Автор: math64 12.9.2012, 15:11 |
| Ты же не даёшь свой полный код - поэтому не могу точно дать ответ. Принцип такой: не давать пользователю доступ непосредственно к объекту, а только через различные обертки. Даже при создании объекта пользователь получает только его обертку. Как это реализовать - без разницы. Тогда ты всегда будешь знать сколько ссылок на объект осталось и когда его можно удалить. Не упомянуто осталось, что если у тебя есть объекты A и В, связанные друг с другом, то удалять их можно только когда счетчики внешних ссылок на оба из них обнулятся или связь между ними разорвётся. |
| Автор: xbarmaglot 12.9.2012, 15:25 | ||
ну я, впринципе, привел пример, который хотел реализовать. Идея в том, что ели парент возвращает созданный объект через указатель, то он его подписывает на себя. Если пользователь забыл его грохнуть, то он грохнется через связь QObject. Если сделать класс свободным, то за время жизни отвечает сам создатель класса. Добавлено через 4 минуты и 32 секунды Остался лишь вопрос - если парент вернет указатель и потом парент грохнут. Он попытается грохнуть созданный им объект, который у меня. Что тогда будет ? Добавлено через 5 минут и 48 секунд В отладке ругается на битую кучу. Получается, что связь по QObject можно делать только для закрытых дочерних классов ? |
| Автор: math64 12.9.2012, 15:44 |
| Так я тебе говорю: твой Parent должен стать приватным классом. Удалить его сможешь только ТЫ (на крайняк объяви приватными конструктор, деструктор и операторы копирования). Доступ к нему пользователем - только через обёртки. Класс удаляется ТОБОЙ когда все обертки будут удалены. Чтобы это проконтролировать - достаточно иметь счётчик числа обёрток. У оберток обязательны конструктор копирования, оператор присваивания и деструктор, в которых будет изменяться счётчик. ЗЫ: Класс наследуемый от QObject должен быть объявлен в заголовке, по которому moc создаёт файл moc_XXXX.cpp Иначе при линковке будут неопределённые символы. Не забудь про макрос Q_OBJECT. |
| Автор: xbarmaglot 12.9.2012, 15:51 | ||||
аааа.... понятно о чем ты говорил
ну удалять его не обязательно. Хотелось бы 1. либо запретить его удалять пока есть обертки 2. либо в отладке выводить разумное сообщение (а не крах кучи Похоже мне сможет помочь лишь boost::shared_ptr и boost::shared_from_this Но я думал, что раз парент в QT может грохать потомков, то защита от такого случая тоже какая-то есть. |
| Автор: xbarmaglot 12.9.2012, 18:52 |
| math64, а может не париться и вообще наследоваться от интерфейсов и просто их реализовать. А раздавать сами интерфейсы. |
| Автор: math64 12.9.2012, 21:14 |
| Можно. Но это не решит проблемы удаления. Выдал кому-то указатель на интерфейс - а затем удалил сам объект. Или наоборот, забыл удалить. А предлагаемый механизм автоматически удаляет объект, когда все обертки удалились. В Qt такая схема используется для QList, в QSqlTableModel и многих других классах. Достаточно просто реализуется с помощью QAtomicInt. qAtomicAssign(), qAtomicDetach(). Но нужно не забывать реализовывать копю коструктор, operator=, иногда operator==, нельзя использовать генерируемые компилятором по умолчанию. Что лучше решать тебе самому, зависит от конкретной задачи. |
| Автор: xbarmaglot 12.9.2012, 21:23 | ||||||||
логично
да закрыть их вообще.
а может вообще всем по рукам надавать
Создать Wrapper нельзя - закрыт конструктор. Копировать нельзя - тоже закрыто. Можно лишь получить ссылку и ее использовать. P.S. Или не городить огород и передать shared_ptr в конструктор Wrapper - тогда там и подсчет ссылок и все остальное |
| Автор: borisbn 13.9.2012, 16:02 |
можно, но можно пытаться использовать её и после удаления Parent'а. В общем, ничем не отличается от варианта с указателем. Вообще ничем. |
| Автор: xbarmaglot 13.9.2012, 16:26 | ||
вот я и думал решить это автоматической отпиской от QObject |
| Автор: borisbn 13.9.2012, 23:26 |
| xbarmaglot, как любит говорить один из участников этого форума "Вы лечите последствия, а не причину" В смысле, думаю, стОит пересмотреть сам подход, а не пытаться найти лазейку в Си++, Qt, etc. Андрей, я прав ? |
| Автор: xbarmaglot 14.9.2012, 22:06 | ||
а что можно предложить взамен ? Мне кажется идея с подсчетом ссылок тоже излишняя. Должно быть решение проще ... |
| Автор: math64 15.9.2012, 20:50 |
| Ну можешь использовать "умные указатели" - но это значит только то, что использование счётчиков (или списков ссылок) будет скрыто от тебя и для счётчиков будет выделяться память отдельно. |