Здравствуйте, es3000.
КЛ>Неверно поставленная задача приводит к неверному решению. Неверное решение порождает массу проблем, которые, как правило, красиво не решаются, а устраняются путем написания "заплаток". Проблема циклических ссылок — из их числа. "Заплатки" постепенно накапливаются, и, в результате, получается тяжелый и несопровождаемый код.
В подтверждение слов Кирилла я бы рекомендовал вам пролистать книжку "Жемчужины программирования", хотя бы первае пару глав (http://shop.piter.com/book/978531800715/). Именно это там и написано, когда разбираются неудачные "полеты". Неверное понимание задачи приводит к неверной формальной постановке, а это — к неверным изначальным техническуим предпосылкам, что, в свою очередь, определяет всю архитектуру (структуры данных, алгоритмы, производительность).
Re[8]: Как правильно реализовать иерархическую структуру объ
ika>У меня закралось подозрение, что, возможно, проблему цикличности решить в полном объеме на c++ не удастся. Возможно, я ошибаюсь. Если только самому не писать надстройку к менеджеру памяти, чтоб он ходил и искал оторванные куски связанных объектов. Либо заворачивать каждый ком-объект в некие прокси, назначение которых — только считать ссылки и говорить результат кому-то выше по первому требованию. Но это едва ли входит в scope прикладной программы.
Спасибо за понимание, наконец-то начали обсуждать задачу
В общем-то идея насчет прокси мне понравилась. Надо это обдумать
Я читал статью по COM где предлагается делать дополнительный объект, который выполняет функции самого объекта. Например:
1) для объекта "Фирма" создать доп.объект "ВнутрФирма"
2) вложить его в объект "Фирма"
3) для объекта "Отдел" установить ссылку на "ВнутрФирма"
Тогда подсчет ссылок будет везде нормальным
Но тогда возникает такая проблема: при обращении Сотрудник.Отдел.Фирма мы получим ссылку не на сам объект "Фирма" , а на его "реализацию" — "ВнутрФирма"
ika>Основная задача — это освобождение памяти при завершении работы программы? Если так, то достаточно помещать каджый полученный экземпляр com-объекта в какое-то глобальное хранилище, а перед завершением программы вызвать у него очистку — чтобы у всех имеющихся объектов были принудительно вызваны DeleteRef до RefCount==0.
Освобождать память хочется не только при завершении, а при каждом освобождении всех "внешних" ссылок на объект. (Если "внешними" назвать ссылки от всех других объектов, кроме вложенных)
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[9]: Как правильно реализовать иерархическую структуру объ
Здравствуйте, es3000, Вы писали:
E>1) для объекта "Фирма" создать доп.объект "ВнутрФирма" E>2) вложить его в объект "Фирма" E>3) для объекта "Отдел" установить ссылку на "ВнутрФирма" E>Тогда подсчет ссылок будет везде нормальным
Я тоже. IMHO, раздувать каждый геттер проперти в каждом классе затычкой — "не те джунлги" (с). Аргументировать не могу. Только интуитивно чувствую, что нехорошо это — базировать архитектуру на решениях-затычках, позаимствованных из инета да еще и не до конца понятых.
Re: Как правильно реализовать иерархическую структуру объект
Здравствуйте, es3000, Вы писали:
E>Напрмер, есть у меня объект "Фирма", он содержит объект "Отдел", а "Отдел" в свою очередь содержит объект "Сотрудник". E>К объекту "Сотрудник" можно обратиться так: E> Фирма.Отдел.Сотрудник E>А теперь я хочу, чтобы для "Сотрудника" можно было узнать в каком "Отделе" на какой "Фирме" он работает, например: E> лФирма = Сотрудник.Отдел.Фирма
Представьте, что фирма со временем превращается в холдинг, состоящий из нескольких фирм. При этом некий сотрудник неформально числится в холдинге, а по бухгалтерии -- в двух фирмах: в одной он занимается, скажем, разработкой, а в другой -- технической поддержкой. Естественно, ни о какой принадлежности сотрудника какому-либо одному отделу речи быть не может. Кроме того, формально, скажем, директор фирмы тоже является сотрудником, и при этом вряд ли принадлежит какому-либо отделу.
Вы уверены, что Ваша иерархия, непосредственно проистекающая из Вашего текущего представления модели предметной области, может быть приспособлена к таким вещам? Проблемы с зацикливанием ссылок могут потом показаться невинной детской забавой.
bloß it hudla
Re[8]: Как правильно реализовать иерархическую структуру объ
КЛ>Прежде чем решать задачу, ее нужно сначала грамотно поставить...
Я с вами во всем согласен, я сам всегда отношусь достаточно серьезно к постановке
Но проблема которую я пытаюсь решить не относится к постановке, она относится к реализации. С заказчиком все обговорено, есть понимание того , что нужно от программы.
Возможность обратиться к сотруднику через фирму и к фирме через сотрудника — это чисто внутренняя реализация, можно и не делать такого обращения вовсе, а выполнять например поиск сотрудников для конкретной фирмы и наоборот поиск фирмы для сотрудника по базе данных по идентификатору. Как уже говорили.
Но согласитесь что программу писать было бы намного удобнее, если бы все-таки работал такой механизм: Фирма.Отдел.Сотрудник, Сотрудник.Отдел.Фирма.
Причем этот механизм работает, программа уже написана, программа получилась короткой, хорошо читаемой, ошибок на данный момент нету, и если что-то надо будет поменять — поменять будет легко, так как этот способ взаимодействия объектов никак не влияет на архитектуру всей программы.
Остается только проблема циклических ссылок и освобождением памяти. Даже и эта проблема уже решена , правда обходным путем, как кто-то советовал при помощи глобального хранителя ссылок, который потом все корректно освобождает.
КЛ>Проблема циклических ссылок решается очень легко. Она просто не создается.
Такая проблема есть, у предлагается много способов ее решения
Посмотрите статью Managing Object Lifetimes in OLE в MSDN
Конечно, там описывается более сложная ситуация, но в принципе очень похожа на мою
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[10]: Как правильно реализовать иерархическую структуру об
ika>Я тоже. IMHO, раздувать каждый геттер проперти в каждом классе затычкой — "не те джунлги" (с). Аргументировать не могу. Только интуитивно чувствую, что нехорошо это — базировать архитектуру на решениях-затычках, позаимствованных из инета да еще и не до конца понятых.
Согласен,
поэтому я и обратился на форум,
может кто-нибудь что-то придумал более правильное решение
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[2]: Как правильно реализовать иерархическую структуру объ
AL>Представьте, что фирма со временем превращается в холдинг, состоящий из нескольких фирм. При этом некий сотрудник неформально числится в холдинге, а по бухгалтерии -- в двух фирмах: в одной он занимается, скажем, разработкой, а в другой -- технической поддержкой. Естественно, ни о какой принадлежности сотрудника какому-либо одному отделу речи быть не может. Кроме того, формально, скажем, директор фирмы тоже является сотрудником, и при этом вряд ли принадлежит какому-либо отделу.
AL>Вы уверены, что Ваша иерархия, непосредственно проистекающая из Вашего текущего представления модели предметной области, может быть приспособлена к таким вещам? Проблемы с зацикливанием ссылок могут потом показаться невинной детской забавой.
Ну на похожий вопрос я уже отвечал (посмотрите пожалуйста выше).
Постановка уже есть, сейчас не время ее обсуждать,
сейчас надо решить чисто техническую часть реализации поставленной задачи
Надо попытаться реализовать такую иерархию и все тут,
если не получится — придется реализовать ту же функциональность но по другому
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: Как правильно реализовать иерархическую структуру объект
Здравствуйте, es3000, Вы писали:
E>Напрмер, есть у меня объект "Фирма", он содержит объект "Отдел", а "Отдел" в свою очередь содержит объект "Сотрудник". E>К объекту "Сотрудник" можно обратиться так: E> Фирма.Отдел.Сотрудник E>А теперь я хочу, чтобы для "Сотрудника" можно было узнать в каком "Отделе" на какой "Фирме" он работает, например: E> лФирма = Сотрудник.Отдел.Фирма E>Если попробовать это реализовать следующим образом: E>... E>То естественно будут циклические ссылки и объект "Фирма" никогда не удалится из памяти:
E>Что говорит теория на этот счет? как правильно реализовать такие связи между объектами?
ИМХО, основные трудности у Вас вызывает смешение двух вопросов:
1) Как организовывать общение Отдела и Фирмы ( чтобы было удобно доступаться из Отдела к Фирме и из Фирмы к Отделу)
2) Как хранить (и удалять) Отделы и Фирмы. В частности, чтобы не оставалось зависших ссылок
Попробуйте разделить эти вопросы и решать их по отдельности.
Например,
В целях 1) При создании всей структуры в памяти можно давать ссылку на Фирму конструктору Отдела (либо через метод Отдел::AddФирма), а ссылку на отдел добавлять через Фирма::AddОтдел. Через
В целях 2) можно хранить Отделы и Фирмы совершенно отдельно и реализовать методы вроде Фирма::DeleteItselfИВсеОтделыЕслиОниНеВходятВДругиеФирмы
P.S.
Всё вышесказанное перекликается с уже высказанным в этой ветке
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Chief Software Engineer,
Scrum Master, Symbian
Re[2]: Как правильно реализовать иерархическую структуру объ
_>В целях 1) При создании всей структуры в памяти можно давать ссылку на Фирму конструктору Отдела (либо через метод Отдел::AddФирма), а ссылку на отдел добавлять через Фирма::AddОтдел. Через _>В целях 2) можно хранить Отделы и Фирмы совершенно отдельно и реализовать методы вроде Фирма::DeleteItselfИВсеОтделыЕслиОниНеВходятВДругиеФирмы
А в какой момент вызывать метод "Фирма::DeleteItselfИВсеОтделыЕслиОниНеВходятВДругиеФирмы"?
Наличие самого метода не решает проблему. Нужно чтобы он вызвался когда освобождается последняя ссылка на объект. А как это определить? В этом то и суть — что последняя ссылка никогда не освободится, если объекты ссылаются друг на друга.
_>Всё вышесказанное перекликается с уже высказанным в этой ветке
Высказываний то много, только никто не предложил решения
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[3]: Как правильно реализовать иерархическую структуру объ
Здравствуйте, es3000, Вы писали:
_>>В целях 1) При создании всей структуры в памяти можно давать ссылку на Фирму конструктору Отдела (либо через метод Отдел::AddФирма), а ссылку на отдел добавлять через Фирма::AddОтдел. Через _>>В целях 2) можно хранить Отделы и Фирмы совершенно отдельно и реализовать методы вроде Фирма::DeleteItselfИВсеОтделыЕслиОниНеВходятВДругиеФирмы
E>А в какой момент вызывать метод "Фирма::DeleteItselfИВсеОтделыЕслиОниНеВходятВДругиеФирмы"? E>Наличие самого метода не решает проблему. Нужно чтобы он вызвался когда освобождается последняя ссылка на объект. А как это определить? В этом то и суть — что последняя ссылка никогда не освободится, если объекты ссылаются друг на друга.
В C++ понятие "освобождается ссылка" — исключительно логическое и виртуальное
Освобождайте тогда, когда надо освобождать. Например, если объектов немного, то при выходе из программы. Причём, если хранить Фирмы и Отделы в, скажем, разных массивах, то всего-то понадобится поудалять всё из этих массивов.
Кроме того, необязательно именно удалять все Отделы фирмы при удалении фирмы. Очень может быть, что быдет достаточно удалять ссылку на фирму.
В общем, всё зависит от логики хранения.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Chief Software Engineer,
Scrum Master, Symbian
Re[4]: Как правильно реализовать иерархическую структуру объ
_>В C++ понятие "освобождается ссылка" — исключительно логическое и виртуальное _>Освобождайте тогда, когда надо освобождать. Например, если объектов немного, то при выходе из программы. Причём, если хранить Фирмы и Отделы в, скажем, разных массивах, то всего-то понадобится поудалять всё из этих массивов. _>Кроме того, необязательно именно удалять все Отделы фирмы при удалении фирмы. Очень может быть, что быдет достаточно удалять ссылку на фирму.
Да на С++, но работа выполняется с СОМ-объектами, которые сами ведут учет своих ссылок, и сами себя освобождают.
А что значит "Освобождайте тогда, когда надо освобождать"??? Надо освобождать, когда нету ссылок на объект.
Хранить-то эти объекты можно и в массивах только они все равно будут друг на друга ссылаться
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: Как правильно реализовать иерархическую структуру объект
To all:
Джентельмены. Вам не кажется что не зная полной постановки конкретной задачи вы судите о реализации. Я могу придумать сотню требований, когда идентификация по ссылкам более удовлетворяет задаче, чем идентификация по идентификатору. Каждой постановке, должно быть наиболее подходящее решение, и на основании вышеперечисленных данных, эффективное решение выбрать невозможно.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: Как правильно реализовать иерархическую структуру объект
Вот как у меня в проекте решается проблема с циклическими ссылками в COM.
Все сущности существуют в рамках бизнес транзакции (UnitOfWork). В этом же UnitOfWork реализован IdentityMap, чтобы объекты не грузились заново и просто для хранения списка всех используемых объектов в текущей бизнес транзакции.
Все объекты имеют метод Shutdown, в котором объект освобождает все ссылки на другие COM объекты, которые у него имеются.
Так вот, после Commit’a бизнес транзакции объекты не должны использоваться, т.е. они должны быть заново прочитаны. Соответственно после Commit’a UnitOfWork пробегает по ВСЕМ зареганным у него объектам, вызывая метод Shutdown, и затем удаляет все объекты из списка. Все ссылки очищаются, объекты удаляются из памяти… Что и требуется получить! Да и сам UnitOfWork после как правило тоже уничтожается, потому что больше не нужен
Единственное…. пришлось в Set и Get методах у всех сущностей добавить код с проверкой состояния shutdown объекта и генерировать исключение, чтобы случайно не использовать уже «мертвый» объект.
Re: Как правильно реализовать иерархическую структуру объект
Здравствуйте, es3000, Вы писали:
E>Напрмер, есть у меня объект "Фирма", он содержит объект "Отдел", а "Отдел" в свою очередь содержит объект "Сотрудник". E>К объекту "Сотрудник" можно обратиться так: E> Фирма.Отдел.Сотрудник E>А теперь я хочу, чтобы для "Сотрудника" можно было узнать в каком "Отделе" на какой "Фирме" он работает, например: E> лФирма = Сотрудник.Отдел.Фирма
E>То естественно будут циклические ссылки и объект "Фирма" никогда не удалится из памяти:
Можно сделать следующее:
— Выкинуть все связи между Фирмой, Отделом и Сотрудником из реализации этих классов
— Управление связями передать сервисному классу
— Для решения задачи дергать соответствующие методы этого сервисного класса
class RelationManager {
// для решения первой задачи
найтиОтделПоФирме();
найтиСотрудникаПоОтделу();
// для решения второй задачи
найтиОтделПоСотруднику();
найтиФирмуПоОтделу();
}
class Отдел {
.....
Сотрудник(){
return RelationManager.найтиСотрудникаПоОтделу(this);
}
.....
}
В этом случае управление связями (и ссылками) будет осуществляться в одном месте, а классы-сущности можно будет безболезненно удалять.
Как развитие данного варианта можно (скорее нужно? ) вообще все запросы осуществлять через сервисный класс (вместо Сотрудник.Отдел.Фирма использовать RelationMAnager.найтиФирмуПоСотруднику), но задача ставилась иначе.
Другие варианты (менее красивые)
— при удалении объекта уведомлять об этом свои внутренние объекты. Так при удалении Фирма вызывает для (каждого) отдела Отдел.обнулитьСвязьСФирмой.
— использовать везде одностороннюю связь, а обратную реализовать через поиск (т.е. связь Фирма.Отдел оставить как есть, а связь Отдел.Фирма удалить и реализовать ее путем поиска — бежи по всем Фирмам, отдел в ней? если ДА — возвращаем результат)
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Best regards, Буравчик
Re[2]: Как правильно реализовать иерархическую структуру объ
Здравствуйте, shev, Вы писали:
S>Вот как у меня в проекте решается проблема с циклическими ссылками в COM.
S>Все сущности существуют в рамках бизнес транзакции (UnitOfWork). В этом же UnitOfWork реализован IdentityMap, чтобы объекты не грузились заново и просто для хранения списка всех используемых объектов в текущей бизнес транзакции.
S>Все объекты имеют метод Shutdown, в котором объект освобождает все ссылки на другие COM объекты, которые у него имеются.
S>Так вот, после Commit’a бизнес транзакции объекты не должны использоваться, т.е. они должны быть заново прочитаны. Соответственно после Commit’a UnitOfWork пробегает по ВСЕМ зареганным у него объектам, вызывая метод Shutdown, и затем удаляет все объекты из списка. Все ссылки очищаются, объекты удаляются из памяти… Что и требуется получить! Да и сам UnitOfWork после как правило тоже уничтожается, потому что больше не нужен
S>Единственное…. пришлось в Set и Get методах у всех сущностей добавить код с проверкой состояния shutdown объекта и генерировать исключение, чтобы случайно не использовать уже «мертвый» объект.
Спасибо за ответ, а то я уже и не надеялся, что кто-то поможет по делу
Ваш способ решения проблемы интересный, но самое главное это будет работать!
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[2]: Как правильно реализовать иерархическую структуру объ
Если делать сервисный класс, то он тоже должен хранить ссылки на объекты. Например, в сервисном классе хранится что какому-то объекту "Отдел" соответствует объект "Фирма". Т.е. сервисный класс так же увеличивает счетчики ссылок этих объектов. И "безболезненно удалять классы-сущности" опять не получается.
Допустим моя программа работает с объектом "Фирма", например какая-то функция "РаботаСФирмой" каким-то образом получает этот объект и что-то с ним делает. В программе также будут объекты "МенеджерСвязей" и "Отдел". В результате на объект "Фирма" будет создано две ссылки: из функции и из "МенеджерСвязей". При выходе из функции я освобождаю ссылку на объект "Фирма", но "МенеджерСвязей" еще хранит свою ссылку и объект не освободится.