LINUX.ORG.RU

Обьекты, использующие части своей фабрики

 ,


0

3

Продолжается мой процесс написания хеллоуворлдов на С++. Известно что многое было сделано в стандарте С++ 11 для того чтобы снизить вероятность ошибок, в том числе в работе с памятью. Хочу проконсультироваться с плюсовиками в плане организации кода.

Допустим есть обьект класса Mothership. В нем есть какие-то данные. Еще есть метод

std::unique_ptr<UFO> launch_ufo();

Он создает обьект и ним можно пользоваться. Mothership не имеет сcылок на UFO, он полностью отдал право пользования внешнему коду, на что часто намекает (но не гарантирует) std::unique_ptr. Но UFO скрыто пользуется частями экземпляра класса Mothership, который его создал. Если инстанс Mothership откинет копыта, то все UFO станут непригодными.

Пример не выдумал и вполне может иметь место с коллекцией и итератором.

Можно написать документацию и по хорошему попросить не уничтожать Mothership. Но можно ли сделать код дуракоустойчивым?

Как с академически правильной будет перерефакторить этот пример, чтобы избавиться от ошибок удаления Mothership раньше времени, чтобы не сломать уже созданные экземпляры UFO, если обязательным условием есть пользование обьектом Mothership из UFO.

Напрашивается что-то в стиле выделение общих частей Mothership и UFO в std::shared_ptr внутри Mothership. Еще идеи?

★★★★★

Сам Mothership можно завернуть в shared_ptr, а в UFO держать на него ссылку shared_ptr или weak_ptr.

mashina ★★★★★
()
Ответ на: комментарий от mashina

Если Mothership - библиотечный класс, то тот кто его создавал мог легко его создать через new и хранить как простой указатель. Он его удалит и все. Можно завернуть его в MothershipManager какой-то и все делать там, но MothershipManager/Mothership ничем не отличается от Mothership/MothershipCore, который описан в топике изначально

vertexua ★★★★★
() автор топика

Тебе нужен супермазершип, у которого будет ланч_уфо() и шаредптр на мазершип. В уфо засунь шаредптр на мазершип и всё будет тип топ. викптр - костыль, ничем от проверки указателя на нуль при каждом обращении не отличающийся.

Напрашивается что-то в стиле выделение общих частей Mothership и UFO в std::shared_ptr внутри Mothership. Еще идеи?

Тоже годная идея.

nanoolinux ★★★★
()
Последнее исправление: nanoolinux (всего исправлений: 1)
Ответ на: комментарий от tailgunner

Мне на надо чтобы все UFO внезапно поняли что Mothership сдох, хоть и достаточно чисто

vertexua ★★★★★
() автор топика
Ответ на: комментарий от vertexua

Если Mothership - библиотечный класс, то тот кто его создавал мог легко его создать через new и хранить как простой указатель

А что именно ты рефакторишь, если ты не можешь рефакторить Mothership?

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Ну я не к тому говорил, просто что выделение разшариваемой части внутри Mothership почти эквивалентно надстраиванию над Mothership еще одного класса, но первое не налагает на сам Mothership никаких ограничений, его легко можно создавать и удалять хоть на стеке, хоть с помощью new/delete

vertexua ★★★★★
() автор топика
Ответ на: комментарий от vertexua

Если Mothership - библиотечный класс, то тот кто его создавал мог легко его создать через new и хранить как простой указатель. Он его удалит и все.

Так обычно не делают в с++11, да и вообще не делают. Если тебе отдали указатель на объект который сам не конструировал через new, то означает (оговаривается в документации к api)

1. тебя сделали владельцем этого объекта и дальше уже должен сам заниматься его уничтожением. Тут проблем нет, заворачиваешь в shared_ptr и всё.

2. Дали указатель и привязали его врмя жизни к какому-то другому объекту (твоему же) или к какой-то области видимости (например, валиден только в колбеке или это синглтон). Тогда ссылаться нужно на гланый родительский объект или не давать жить порождённому UFO вне скопа.

Т.е. это обычные разумные соображения на счёт дизайна кода и библиотек. с++11 сюда только добавляет shared_ptr, т.е. тебе бы отдали не просто указатель, а указатель завёрнутый сразу в {shared, weak, uniqe}_ptr - uniqe~ передаёт полностью владение, а остальное даёт попользоваться на время.

mashina ★★★★★
()

Но UFO скрыто пользуется частями экземпляра класса Mothership, который его создал

Но можно ли сделать код дуракоустойчивы

Тебе нужен observer. ufo подписывается на события mothership. Когда mothership откидывает копыта, он уведомляет всех ufo - я сдох, решайте что делать.

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

Я написал

пользуется частями экземпляра

Например они указывают на части большого буфера. Буфер должен оставаться

vertexua ★★★★★
() автор топика
Ответ на: комментарий от vertexua

Буфер должен оставаться

А-ааа. Вот оно чо. Если буфер должен оставаться, то буфер - отдельная сущность и должен быть отдельным классом, а не частью mothership.

no-such-file ★★★★★
()
Ответ на: комментарий от vertexua

Если Mothership - библиотечный класс, то тот кто его создавал мог легко его создать через new и хранить как простой указатель.

Чтобы внутри launch_ufo() ты мог передать shared_ptr на себя создаваемому UFO, тебе придётся унаследовать Mothership от enable_shared_from_this<Mothership>. Это довольно толсто намекнёт пользователю, как нужно создавать объект. Если пользователь всё-таки дурак, то спрячь конструктор в статичный метод, возвращающий shared_ptr.

const86 ★★★★★
()
Ответ на: комментарий от vertexua

О, круто, о таком и не слышал

Почитай описание стандартной библиотеки в стандарте (могу финальный C++11 скинуть). Просто идеальный справочник, и заодно, полный обзор возможностей.

Pavval ★★★★★
()

[офтоп]

Он создает обьект и ним можно пользоваться.

и ним

В который раз замечаю эту ошибку у тебя. Запомни, «н» добавляется к местоимениям третьего лица (он, оно, она, они), когда они используются с предлогами: «в нем», «у ней», «к ним». Когда предлогов нет, «н» не используется. Исключение: местоимение «мы» — всегда с «н».

Virtuos86 ★★★★★
()
Ответ на: комментарий от nanoolinux

викптр - костыль, ничем от проверки указателя на нуль при каждом обращении не отличающийся.

В данном случае я тоже за shared_ptr, но всё-таки weak_ptr от простого указателя отличается. Так как имея простой указатель вообще невозможно узнать когда он станет невалидным. И проверка на нул ничего не даст.

DarkEld3r ★★★★★
()
Ответ на: комментарий от DarkEld3r

Да, там по ссылке он и был, я его и стянул.

Adonai ★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.