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

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

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Manager + shared  (Прочитано 11267 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« : Август 18, 2016, 11:06 »

Добрый день

Вот разбираюсь в обильном чужом коде. Есть система "менеджеров" (читай синглтонов) которые хранят мапы имя->объект одного типа. Пример
Код
C++ (Qt)
// создаем skeleton
Skeleton * sk1  = new Skeleton("Skeleton 1");
 
// регистрируем его в менеджере
scene->getSkeletonManager()->addSkeleton(sk1);
 
Теперь мы можем брать объект по имени и удалять его
Код
C++ (Qt)
Skeleton * sk =  scene->getSkeletonManager()->getSkeleton("Skeleton 1");
scene->getSkeletonManager()->removeSkeleton("Skeleton 1");
 
Подобную организацию я видел не раз, не скажу что это "плохо".

НО - тут же начинаются пляски с шаред пойнтером. Вот меня это как-то смутило. Ведь если "менеджер" берет на себя "ownership" то все удаления должны идти через него. С др стороны шаред грохнет если ноль ссылок.

Как Вы думаете - могут эти 2 подхода "мирно сосуществовать"? Или это несомненно "косяк архитектуры"?

Спасибо

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

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #1 : Август 18, 2016, 11:13 »

Если деструктор Skeleton корректно сообщает менеджеру о своей "смерти", то все ок.
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
ssoft
Программист
*****
Offline Offline

Сообщений: 584


Просмотр профиля
« Ответ #2 : Август 18, 2016, 11:23 »

На самом деле не ясно, как внутри менеджера храниться объект. В представленном примере владение уникальное, а все указатели на объект - это всего лишь ссылки без контроля владения.

Если возможен многопоточный доступ к менеджеру, то такой указатель в любой момент может стать невалидным (из-за возможности удаления) и это "косяк архитектуры". Если заменить простые указатели на shared_ptr, то это решит проблему с валидностью объекта, но может создать проблемы (не обязательно) с перекрестными ссылками. Поэтому лучше вместо простых указателей использовать weak_ptr, преобразуя их в shared_ptr во время работы с объектом.

В данном случае - если многопоточный доступ отсутствует, то в данных ограничениях решение валидное; если многопоточный доступ присутствует, то имеется "косяк архитектуры".
Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #3 : Август 18, 2016, 11:38 »

В данном случае - если многопоточный доступ отсутствует, то в данных ограничениях решение валидное; если многопоточный доступ присутствует, то имеется "косяк архитектуры".

Тогда это будет косяк имплементации, а не архитектуры.
С "архитектурой" тут проблем нет.
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
ssoft
Программист
*****
Offline Offline

Сообщений: 584


Просмотр профиля
« Ответ #4 : Август 18, 2016, 11:41 »

Тогда это будет косяк имплементации, а не архитектуры.
С "архитектурой" тут проблем нет.

Согласен Подмигивающий
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #5 : Август 18, 2016, 12:05 »

"Многопоточность" отсутствует.
Поэтому лучше вместо простых указателей использовать weak_ptr, преобразуя их в shared_ptr во время работы с объектом.
Если имеется ввиду "менеджер хранит weak_ptr", то

1) Сейчас менеджер грузит объекты не заботясь о том кто их юзает (может пока и никто). Чем заменить этот ф-ционал если он хранит weak?

2) Что делать с
Код
C++ (Qt)
scene->getSkeletonManager()->removeSkeleton("Skeleton 1");
? Через weak_ptr никого не удалить

В общем так менеджер теряет ownership и становится чем-то типа "наблюдающего" (пусть и полезного)
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Август 18, 2016, 14:15 »

Если деструктор Skeleton корректно сообщает менеджеру о своей "смерти", то все ок.
Житейски разумно, но явно "не айс" (як каже молодь). Чего это "младший" дает указания "менеджеру", вообще чего он знает о существовании менеджера?

И это не решает коллизии "менеджер грохает используемого"
Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 584


Просмотр профиля
« Ответ #7 : Август 18, 2016, 14:29 »

Если имеется ввиду "менеджер хранит weak_ptr", то ...

Ни в коем случае). Менеджер хранит shared_ptr, а вот предоставляет weak_ptr. Тогда в месте использования можно усилить weak_ptr до shared_ptr и локально контролировать время жизни объекта. Даже если менеджер удалит объект, грохнется он только после удаления последнего shared_ptr.
Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #8 : Август 18, 2016, 15:35 »

Чего это "младший" дает указания "менеджеру", вообще чего он знает о существовании менеджера?

Менеджер при создании объекта "говорит" ему, кто хозяин:

Skeleton* Manager::AddSkeleton()
{
  Skeleton* slave = new Skeleton();
  slave->setParent(this);
  return slave;
}

А при смерти slave в этом случае он просто получает информацию о событии:

Skeleton::~Skeleton()
{
  if (m_parent)
    m_parent->slaveKilled(this);
}

Тогда никаких проблем не возникнет.

И это не решает коллизии "менеджер грохает используемого"

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

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
_Bers
Бывалый
*****
Offline Offline

Сообщений: 486


Просмотр профиля
« Ответ #9 : Август 18, 2016, 22:03 »

Добрый день
Как Вы думаете - могут эти 2 подхода "мирно сосуществовать"? Или это несомненно "косяк архитектуры"?

да. могут.
shared_ptr позволяет гибкие стратегии владения ресурсами.
Записан
_Bers
Бывалый
*****
Offline Offline

Сообщений: 486


Просмотр профиля
« Ответ #10 : Август 18, 2016, 22:04 »

Даже если менеджер удалит объект, грохнется он только после удаления последнего shared_ptr.

не факт.
зависит от бизнес-логики менеджера.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #11 : Август 19, 2016, 06:11 »

да. могут.
shared_ptr позволяет гибкие стратегии владения ресурсами.
К слову: а по-моему с гибкостью у него проблемы. Напр я рассчитывал на удаление объекта, но по каким-то причинам его нет. Как узнать "кто держит"?

Ну ладно, так что - менеджер должен хранить (вместо обычных указателей как сейчас)
Код
C++ (Qt)
typedef std::map<std::string, shared_ptr<Skeleton> > TMap;
Тогда все что попало в менеджер остается неубиенным. А если менеджер удалит свой шаред из мапы - еще хуже: значит объект уже загружен, а в менеджере его нет - действующий через менеджер вероятно загрузит еще копию. Где же (гибкая) стратегия владения?
« Последнее редактирование: Август 19, 2016, 06:15 от Igors » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #12 : Август 20, 2016, 09:30 »

И это не решает коллизии "менеджер грохает используемого"

Тогда менеджер просто получит вызов slaveKilled с поинтером на прибиваемый объект, но он же об этом в курсе Улыбающийся
Менеджер не в курсе в каком(их) шаред пойнтере хранится этот поинтер
Менеджер при создании объекта "говорит" ему, кто хозяин:

Skeleton* Manager::AddSkeleton()
{
  Skeleton* slave = new Skeleton();
  slave->setParent(this);
  return slave;
}

А при смерти slave в этом случае он просто получает информацию о событии:

Skeleton::~Skeleton()
{
  if (m_parent)
    m_parent->slaveKilled(this);
}

Тогда никаких проблем не возникнет.
Есть одна система управления/ownership  (менеджер). Вы предлагаете добавить еще другую (parent-child).. Это будет работать только в случае m_parent == manager. Тогда зачем заводить m_parent, slaveKilled и.т.п. если можно действовать через тот же синглтон
Код
C++ (Qt)
Skeleton::~Skeleton( void )
{
...
scene->getSkeletonManager()->takeSkeleton(this->getName());
}
 
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #13 : Август 20, 2016, 09:46 »

Где же (гибкая) стратегия владения?

shared+weak в манагере.

Код:
{
    auto newSkeleton = std::make_shared<Skeleton>();
    manager->addSkeleton(newSkeleton, "name");
}

{
    auto skeleton = manager->getSkeleton("name");
    manager->removeSkeleton("name"); // skeleton всё еще держит овнершип
    auto skeleton2 = manager->getSkeleton("name");
    Q_ASSERT(skeleton == skeleton2); // true, манагер хранит вик на старый скелетон и вернет нам его
}

{
    auto newSkeleton = std::make_shared<Skeleton>();
    manager->addSkeleton(newSkeleton, "name"); // а вот тут засунули новый инстанс, можно ругаться, если вик ещё живой
    auto skeleton = manager->getSkeleton("name");
    Q_ASSERT(skeleton == newSkeleton);  // этот скелетон не равен тому, что был в предыдущем скопе
}

Записан
_Bers
Бывалый
*****
Offline Offline

Сообщений: 486


Просмотр профиля
« Ответ #14 : Август 20, 2016, 14:33 »

да. могут.
shared_ptr позволяет гибкие стратегии владения ресурсами.
К слову: а по-моему с гибкостью у него проблемы. Напр я рассчитывал на удаление объекта, но по каким-то причинам его нет. Как узнать "кто держит"?

Ну ладно, так что - менеджер должен хранить (вместо обычных указателей как сейчас)
Код
C++ (Qt)
typedef std::map<std::string, shared_ptr<Skeleton> > TMap;
Тогда все что попало в менеджер остается неубиенным. А если менеджер удалит свой шаред из мапы - еще хуже: значит объект уже загружен, а в менеджере его нет - действующий через менеджер вероятно загрузит еще копию. Где же (гибкая) стратегия владения?

ничего не понял.
что значит "рассчитывал на удаление объекта" ?

http://www.cyberforum.ru/cpp-beginners/thread1500101.html#post7882976
« Последнее редактирование: Август 20, 2016, 14:35 от _Bers » Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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