Ух! Стоило отвлечся и понаписали))).
Внесу свой вклад в обсуждение (чтобы еще больше всех запутать).
Объектно-ориентированная модель является первичной по отношению к объектно ориентированной программе.
При этом одну и ту же модель можно реализовать совершенно разными способами.
Рассмотрим модель, представленную на рисунке. На ней представлен ресурс, владелец ресурса и пользователи ресурса.
Владелец композитно владеет ресурсом в соотношении 1 владелец - 1 ресурс.
Пользователи имеют только ассоциативную связь с ресурсом в соотношении много пользователей - 1 ресурс.
Существует большое количество разнообразных способов реализации данной модели, каждая из которых обладает определенными свойствами.
1. Простейший способ реализации
C++ (Qt)
struct Owner
{
Resource m_resource;
};
Распределение ресурса по месту владельца.
Нельзя извлечь ресурс и сломать ассоциативные связи с ним.
Гарантированное отношение 1 владелец - 1 ресурс.
Потоко небезопасный доступ к ресурсу.
C++ (Qt)
struct User
{
Resource & m_resource;
};
Неизменяемая ассоциация с ресурсом.
Отсутствие контроля корректности ассоциативной связи с ресурсом.
Гарантированное отношение много пользователей - 1 ресурс.
Потоко небезопасный доступ к ресурсу.
Возможен такой вариант
C++ (Qt)
struct User
{
::std::reference_wrapper< Resource > m_resource;
};
Изменяемая ассоциация с ресурсом.
Отсутствие контроля корректности ассоциативной связи с ресурсом.
Гарантированное отношение много пользователей - 1 ресурс.
Потоко небезопасный доступ к ресурсу.
2. Может быть выбран способ реализации через raw указатели, но тогда программа усложняется
C++ (Qt)
struct Owner
{
Resource * m_resource = nullptr;
Owner () : m_resource( new Resource ) {}
~Owner () { delete m_resource; }
Owner ( Owner && other ) { ::std::swap( m_resource, other.m_resource ); }
Owner ( const Owner & other ) : m_resource( new Resource( *other.m_resource ) ) {}
};
Распределение ресурса в куче.
Можно сломать ассоциативные связи с ресурсом.
Контроль отношения 1 владелец - 1 ресурс лежит на программисте.
Потоко небезопасный доступ к ресурсу.
C++ (Qt)
struct User
{
Resource * m_resource;
User ( Resource & resource ) : m_resource( ::std::addressof( resource ) );
};
Изменяемая ассоциация с ресурсом.
Отсутствие контроля доступа к ресурсу.
Контроль отношения много пользователей - 1 ресурс лежит на программисте.
Потоко небезопасный доступ к ресурсу.
3. Реализация через unique_ptr
C++ (Qt)
struct Owner
{
::std::unique_ptr< Resource > m_resource;
Owner () : m_resource( ::std::make_unique< Resource >() ) {}
Owner ( const Owner & other ) : m_resource( ::std::make_unique< Resource >( *other.m_resource ) ) {}
};
Распределение ресурса в куче.
Можно сломать ассоциативные связи с ресурсом.
Контроль отношения 1 владелец - 1 ресурс лежит на программисте.
Потоко небезопасный доступ к ресурсу.
Подойдет любая реализация User из вариатнов выше.
4. Реализация через shared_ptr
C++ (Qt)
struct Owner
{
::std::shared_ptr< Resource > m_resource;
Owner () : shared_ptr( ::std::make_shared< Resource >() ) {}
Owner ( Owner && other ) { ::std::swap( m_resource, other.m_resource ); }
Owner ( const Owner & other ) : m_resource( ::std::make_unique< Resource >( *other.m_resource ) ) {}
};
Распределение ресурса в куче.
Можно сломать ассоциативные связи с ресурсом.
Контроль отношения 1 владелец - 1 ресурс лежит на программисте.
Потоко небезопасный доступ к ресурсу.
Такая реализация прямо не соответствует композитной связи из модели и требует аккуратного использования.
Сложно гарантировать (тем более, когда разработчиков много), что случайно не возникнет совместного владения ресурсом.
Но именно такая реализация позволяет контролировать доступ к ресурсу.
Кроме реализация User из вариатнов выше, может быть такая
C++ (Qt)
struct User
{
::std::weak_ptr< Resource > m_resource;
User ( ::std::shared_ptr< Resource > resource ) : m_resource( resource );
};
Изменяемая ассоциация с ресурсом.
Наличие контроля доступа к ресурсу.
Контроль отношения много пользователей - 1 ресурс лежит на программисте.
Потоко небезопасный доступ к ресурсу.
В такой реализации контроль доступа осуществляется посредством разделения владения ресурсом с активностью, а не с пользователем.
Таким образом вид ассоциативных связей с точки зрения модели не нарушается.
Контроль доступа к ресурсу может осуществлен и другими способами, не только связкой shared/weak, например, с помощью mutex, или учетом всех ассоциаций, или совместным владением raw указателя на ресурс, или др. При этом можно контролировать и другие свойства, такие как потоко безопасность, ленивые вычисления и т.п.
Всё что понаписано выше - это примеры того, как одна и та же модель реализуется с помощью разных примитивов языка C++ и библиотеки std. Для контроля разных дополнительных свойств, необходимых в конкретной программе, этих примитивов не достаточно, и требуется дополнительный контроль корректности использования ассоциативных связей со стороны программиста.
C++ Object Token Library предоставляет примитивы, которые контроль корректности использования ассоциативных связей, перекладывают на компилятор. Некий синтаксический сахар, чтобы случайно не выстрелить себе в ногу).
Для тех, кто не готов отдать контроль корректности использования ассоциативных связей компилятору, эта библиотека не нужна.