Вопрос разработки ООП (реализация MFC C ++) - PullRequest
0 голосов
/ 22 июля 2011

У меня есть графический интерфейс для взаимодействия с пользователем, но у меня возникла проблема с дизайном ООП.

Через диалоговое окно пользователь указывает CDiscreteDistribution s, и они сохраняются в std::vector<CDiscreteDistribution*> в классе MyAppDoc для сериализации. Через другое диалоговое окно пользователь выбирает тип CDistribution для конкретного CParameter. CDiscreteDistribution, CConstantDistribution и CContinuousDistribution наследуют CDistribution, а CParameter имеет полиморфный указатель на переменную-член CDistribution. MyAppDoc имеет класс контейнера CParameter. Таким образом, CDiscreteDistribution указывают два дважды, но существуют только один раз.

В итоге, MyAppDoc имеет

  1. std::vector<CDiscreteDistribution*>
  2. CContainer, который имеет много CParameter, которые имеют
    • CDistribution*, который может указывать на один из
      • CDiscreteDistribution, который является одним из CDiscreteDistribution* s, сохраненных выше
      • CConstantDistribution создано / уничтожено CParameter
      • CContinuousDistribution создано / уничтожено CParameter

Этот шаблон проектирования вызывает у меня различные кошмары при портировании приложения на использование shared_ptr из-за двойного удаления и сериализации (повышение). Должен ли один из указателей на CDiscreteDistribution быть weak_ptr? Если да, то где должен принадлежать указатель?

Спасибо за любую помощь!


EDIT: Я переосмыслил причину наличия std::vector<CDiscreteDistribution*>, и это было просто для того, чтобы избежать копирования вектора в и из GUI. Но объекты довольно маленькие, и поэтому я разорвал связь между ними и перенес незначительные последствия для производительности. Теперь MyAppDoc имеет:

  1. std::vector<CDiscreteDistribution>
  2. CContainer, который имеет много CParameter, которые имеют
    • CDistribution*, который может указывать на один из
      • CDiscreteDistribution создано / уничтожено CParameter, скопировано с одного из CDiscreteDistribution х, хранящихся выше
      • CConstantDistribution создано / уничтожено CParameter
      • CContinuousDistribution создано / уничтожено CParameter

Я думаю, что часть проблемы заключалась в том, что boost::serialization сделал два shared_ptr с для каждого CDiscreteDistribution, которые не знали о существовании друг друга. Теперь единственной проблемой является обратная совместимость с файлами, созданными в предыдущих версиях.

Я полагаю, что это "решение" на самом деле просто избегает правильного дизайна!

Ответы [ 2 ]

1 голос
/ 22 июля 2011

Я согласен с Роэлом в том, что вопрос не полностью уточнен.Но, выполнив несколько обширных преобразований из необработанных указателей в shared_ptr, я могу дать вам небольшой совет.

  1. weak_ptr не требуется, если у вас нет циклических зависимостей.Другими словами, если объект A имеет shared_ptr для объекта B, а объект B имеет shared_ptr назад к объекту A. В этом случае для счетчика ссылок любого указателя невозможно перейти к 0, поэтому вы былибо нужно вручную вмешаться, чтобы разорвать цикл, либо использовать weak_ptr, чтобы обозначить одну сторону как зависимую.
  2. Я запутался, почему у вас возникают проблемы с двойным удалением при использовании shared_ptr.Одним из преимуществ умных указателей в целом является то, что вам не нужно фактически удалять их.Если вы преобразовали все ваши необработанные указатели в shared_ptr, у вас не должно быть этой проблемы.Если ваши CConstantDistribution и CContinuousDistribution объекты на самом деле являются локальными, а не выделены с помощью new (я не могу сказать 100%, если это так из вашего описания), вы можете сделать их shared_ptr объектами, которые инициализируются вваш конструктор, если вы можете изменить код приложения.Это позволит вам сделать ваш std::vector<CDiscreteDistribution*> контейнером от shared_ptr до CDiscreteDistribution.На этом этапе вам вообще не нужно беспокоиться об удалении этих объектов, если у вас нет циклических ссылок, как описано выше.Даже если бы вы это сделали, вы бы преобразовали сбой с двойным удалением в утечку памяти, что, как правило, не так уж и плохо.
  3. Сериализация может быть сложной.Поскольку вы пометили вопрос с помощью MFC, я предполагаю, что вы используете сериализацию MFC.У меня обычно нет проблем при переносе всего в shared_ptr при сериализации в файл - я просто использую .get() в объекте интеллектуального указателя и сериализую результирующий необработанный указатель.Когда я сериализирую, я читаю необработанный указатель из сериализованного файла и оборачиваю его в конфетное покрытие shared_ptr в этот момент.Это немного лишний код в функции сериализации, но он работает.

Если я не совсем точно угадала вашу ситуацию, добавьте комментарий.Буду рад помочь, если смогу.

1 голос
/ 22 июля 2011

Вопрос описан недостаточно, чтобы понять полную ситуацию, сложности и точную проблему, но в целом -

  • Я предполагаю, что вы хотите использовать shared_ptr, чтобы не пришлось вручную удалять объекты ()

  • Если это так, посмотрите, можете ли вы решить эту проблему, не используя shared_ptr, а вместо этого используя boost :: ptr_vector вместо вектора необработанных указателей; ptr_vector будет обрабатывать управление памятью для вас.

Я даже не уверен, что принесет вам shared_ptr - из моего ограниченного понимания ситуации совершенно очевидно, что Док владеет объектами CDiscreteDistribution. Кто бы ни владел двумя другими типами Распределений, ответственен за их удаление; это может быть сделано через shared_ptr или иначе. (вы говорите «локально экземпляры», но это мало что значит - они создаются в куче или стеке? Каково их время жизни? Почему их время жизни отличается от объектов DiscreteDistribution? )

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...