Во-первых, в некоторых случаях для защиты умных указателей в многопоточных приложениях использовался не механизм подсчета ссылок, а механизм клонирования объектов, на которые указывали умные указатели. Для этого класс oess_1::stdsn::shptr_t был расширен несколькими методами (oess_shptr_assign, oess_shptr_reset) с тем, чтобы их можно было переопределять в производных классах.
Во-вторых, в v.1.2.0 появился механизм oess_1.2.0. Наследование расширением (subclassing_by_extension). Для работы с объектами, которые поддерживают этот механизм так же требовалось использовать атрибуты-указатели. И для облегчения работы с ними так же требовался класс умного указателя. Но применить для этих целей oess_1::stdsn::shptr_t было невозможно. Дело в том, что oess_1::stdsn::shptr_t представлялся в DDL как:
{type oess_1::stdsn::shptr_t {attr m_ptr {of {ptr} oess_1::stdsn::serializable_t} } }
{type some_smart_pointer_t {attr m_ptr {of {extension_of} some_type_t}} }
Для того, чтобы поддержать умные указатели для механизма subclassing by extension потребовалось бы создать новый тип умных указателей. Но зачем же иметь в ObjESSty несколько разных классов с одинаковой функциональностью и предназначенных для одинаковых целей? Вместо этого был создан каркас для умных указателей, oess_1::stdsn::shptr_skeleton_t, который можно использовать для поддержки механизма subclassing by extension. А так же класс oess_1::stdsn::shptr_t сделан наследником oess_1::stdsn::shptr_skeleton_t для того, чтобы унаследовать всю имеющуюся функциональность.
Класс oess_1::stdsn::shptr_skeleton_t содержит функциональность по управлению хранимым в нем указателем, но не имеет собственного DDL описания. Атрибут oess_1::stdsn::shptr_skeleton_t::m_ptr (указатель на контролируемый объект) должен быть объявлен в DDL описании производного от shptr_skeleton_t класса.
Класс shptr_skeleton_t поддерживает разные политики владения указателем. Т.е. он может использоваться как для реализации владения на основе подсчета ссылок, на основе клонирования объекта, на основе реализованной пользователем политики. Для этого одним из параметров шаблона oess_1::stdsn::shptr_skeleton_t является класс Own_policy. Класс shptr_skeleton_t владеет атрибутом m_own_policy, который и является реальной политикой, управляющей временем жизни контролируемого объекта. Меняя при инстанциировании shptr_skeleton_t типы политик можно достигать разного поведения shptr_skeleton_t. Подробнее о политиках владения см. Политики владения.
1. Описать на DDL схему данных умного указателя. Обязательно указать в ней атрибут m_ptr соотвествующего типа. Например, для простых умных указателей:
{type my_smart_ptr_t {attr m_ptr {of {ptr} my_class_t}} }
{type my_smart_ptr_t {attr m_ptr {of {extension_of} my_class_t}} }
Важно здесь вот что:
2. Описать на C++ свой класс умного указателя следующим образом:
class my_smart_ptr_t : public oess_1::stdsn::shptr_skeleton_t< my_class_t > { // Может так же использоваться макрос OESS_SERIALIZER_EX(). OESS_SERIALIZER( my_smart_ptr_t ) OESS_1_SHPTR_IFACE( my_smart_ptr_t, my_class_t, oess_1::stdsn::shptr_skeleton_t< my_class_t > ) };
template< class T > class policy_t { public : policy_t( T * & pointer_holder ); policy_t( T * & pointer_holder, T * pointer ); ~policy_t(); void reassign(); void link( const policy_t< T > & owner_policy ); std::auto_ptr< T > release(); };
Фокус с объектами-политиками состоит в том, что им класс shptr_skeleton_t передает ссылку на свой атрибут m_ptr. И объекты-политики должны корректно устанавливать или обнулять его значение. Практически во всех случаях именно объект-политика устанавливает значение атрибута m_ptr (в своих конструкторах, методах link и release). Единственным исключением является метод reassign, но о нем речь зайдет ниже.
Первый конструктор необходим для случая, когда shptr_skeleton_t инициализируется конструктором по-умолчанию.
Второй конструктор необходим, когда в конструктор shptr_skeleton_t передается объект, которым никто не владеет. Единственным владельцем должен стать данный объект-политика.
Метод link вызывается в операторе копирования класса shptr_skeleton_t. Его атрибутом является объект-политика из объекта shptr_skeleton_t в правой части присваивания.
Метод release() вызывается либо из метода oess_1::stdsn::shptr_skeleton_t::destroy() (когда пользователь хочет отказаться от владения объектом), либо из метода oess_1::stdsn::shptr_skeleton_t::oess_pre_unpack() (когда текущий контролируемый объект становится неактуальным, т.к. после десериализации контролируемым должен стать другой объект). Должен вовращаться std::auto_ptr, в котором находится указатель на ранее контролировавшийся объект, если его больше никто не контролирует (т.е. объект будет уничтожен std::auto_ptr). Либо в std::auto_ptr должен быть нулевой указатель (т.е. объект продолжает контролировать кто-то еще и объект не может быть физически уничтожен).
Отдельная ситуация с методом reassign(). В большинстве случаев именно объект-политика управляет значением атрибута m_ptr класса shptr_skeleton. Но есть одно исключение -- при десериализации объекта значение атрибута m_ptr устанавливается самой ObjESSty. Поэтому в методе oess_1::stdsn::shptr_skeleton_t::oess_post_unpack() вызывается метод reassign() чтобы объект-политика могла создать всю необходимую инфраструктуру для котроля за новым объектом.
Для того, чтобы тип мог использоваться совместно с политикой cloneable_policy_t необходимо, чтобы он предоставлял метод:
T *
clone() const;
Либо, метод clone() может иметь следующий прототип:
std::auto_ptr< T >
clone() const;
Данная политика делает умный указатель не столько умным, сколько расточительным, т.к. на каждую операцию копирования умного указателя приходится операция клонирования контролируемого объекта. Однако, эта политика может оказаться удобной в многопоточных программах, где умные указатели передаются между потоками и могут сохраняться в каких-то потоках для последующей работы с ними.
Для остальных клиентов класса shptr_t будет видно только одно изменение: методы get() теперь порождают исключения, если приведение типов невозможно. В предыдущих версиях shptr_t в таких случаях возвращался нулевой указатель.