/*!
\page oess_1__pointer_attr	oess_1: Атрибуты-указатели: их назначение и использование

\section oess_1__pointer_attr__purpose Назначение атрибутов-указателей

\subsection oess_1__pointer__attr__purpose__polymorphic	Полиморфные типы

Атрибуты-указатели в ObjESSty поддерживаются для предоставления возможности
сериализации объектов полиморфных типов. В некоторых случаях не известно
заранее, какой объект будет артрибутом сериализуемого объекта. Известно только,
какому базовому типу он принадлежит:

\code
// Базовый тип для всех изображений.
class	image_t
	:	public oess_1::stdsn::serializable_t
	{
		OESS_SERIALIZER( image_t )
	public :
		virtual ~image_t();
		...
	};

// Тип, который использует изображения.
class	scheme_item_t
	:	public oess_1::stdsn::serializable_t
	{
		OESS_SERIALIZER( scheme_item_t )
	private :
		// Подпись под элементом.
		std::string	m_title;
		// Изображение для элемента.
		image_t *	m_image;

	public :
		...
	};
\endcode

Что на DDL представляется следующим образом:
\verbatim
{type	image_t
	|| Тег {super} не указывается, т.к. тип производен от serializable_t.
	...
}

{type	scheme_item_t
	{attr m_title {of std::string}}
	{attr m_image {of {ptr} image_t}}
}
\endverbatim

Со временем может быть создано много классов для представления изображений:

\code
// Базовый тип для растровых изображений.
class	raster_image_t
	:	public image_t
	{
		OESS_SERIALIZER( raster_image_t )
	...
	};

// Изображение в формате GIF.
class	gif_image_t
	:	public raster_image_t
	{
		OESS_SERIALIZER( gif_image_t )
	...
	};

// Изображение в формате JPEG.
class	jpeg_image_t
	:	public raster_image_t
	{
		OESS_SERIALIZER( jpeg_image_t )
	...
	};

// Базовый тип для векторных изображений.
class	vector_image_t
	:	public image_t
	{
		OESS_SERIALIZER( vector_image_t )
	...
	};

// Изображение в формате SVG.
class	svg_image_t
	:	public vector_image_t
	{
		OESS_SERIALIZER( svg_image_t )
	...
	};
\endcode

Что на DDL представляется следующим образом:
\verbatim
{type	raster_image_t
	{super image_t}
	...
}

{type	gif_image_t
	{super raster_image_t}
	...
}

{type	jpeg_image_t
	{super raster_image_t}
	...
}

{type vector_image_t
	{super image_t}
	...
}

{type svg_image_t
	{super vector_image_t}
	...
}
\endverbatim

При сериализации атрибута scheme_item_t::m_image ObjESSty сохранит в
сериализованном представлении реальное имя типа, которому принадлежит
объект-изображение. При десериализации ObjESSty сначала извлекает имя типа,
ищет специальную фабрику для этого типа и создает объект-изображение. После
чего производится десериализация объекта-изображения. Если фабрики для
объекта-изображения нет, то десериализация прерывается исключением.

Для того, чтобы иметь возможность при десериализации создавать объекты
полиморфных типов, ObjESSty строит для каждого сериализуемого типа специальную
фабрику. ObjESSty так же поддерживает список всех фабрик, определенных в
приложении. При десериализации атрибута-указателя этот список просматривается в
поисках необходимой фабрики. Технически, этот механизм реализуется с помощью
типов oess_1::stdsn::factory_registrator_t и oess_1::stdsn::obj_factory_t.

\subsection oess_1__pointer__attr__purpose__optional_attr	Опциональные атрибуты

Кроме механизма поддержки опциональных атрибутов (см. \ref
oess_1_2_0__optional_fields) могут быть случаи, когда какой-то параметр
(атрибут) для объекта может быть либо определен, либо нет. Например, пусть есть
элемент изображения:
\code
class	scheme_item_t
	:	public oess_1::stdsn::serializable_t
	{
		OESS_SERIALIZER( scheme_item_t )
	private :
		// Надпись под элементом.
		std::string	m_title;

		// Параметры шрифта для надписи (шрифт, обычный/курсив/жирный,
		// подчертнутый/перечеркнутый, цвет, угол наклона, ...).
		// Если параметры не заданы, то должен использоваться текущий шрифт.
		// Хранить в этом случае параметры шрифта в объекте не выгодно.
		// Поэтому, если собственные параметры шрифта для объекта не
		// заданы, то этот указатель содержит 0.
		font_params_t * m_font_params;
	...
	};
\endcode

\verbatim
{type	scheme_item_t
	{attr m_title {of std::string}}
	{attr m_font_params {of {ptr} font_params_t}}
}
\endverbatim

При сериализации атрибутов-указателей ObjESSty проверяет, равен ли указатель 
нулю. Если равен, то в сериализованном представлении сохраняется признак
отсутствия значения атрибута. При десериализации этот признак обрабатывается
и атрибуту-указателю присваивается нулевое значение.

\subsection oess_1__pointer__attr__purpose__pointer_containers Контейнеры указателей

Важной особенностью ObjESSty является то, что ObjESSty поддерживает возможность
работы со стандартными STL-контейнерами, которые содержат указатели на
сериализуемые объекты. Главным применением для них является хранение списков
(vector, list, deque) или карт (map, multimap) полиморфных объектов.
Например, некоторое технологическое изображение, состоящее из полиморфных
элементов типа scheme_item_t, может быть описано так:
\verbatim
{type	scheme_t
	{attr	m_items
		|| Порядок элементов важен, поэтому используем std::vector.
		{stl-vector}
		|| Элементами вектора могут быть любые классы, производные от
		|| scheme_item_t.
		{of {ptr} scheme_item_t}
	}
	...
}
\endverbatim

\section oess_1__pointer_attr__dangers	Опасности использования атрибутов-указателей

\subsection oess_1__pointer_attr__dangers__cyclic_ref ObjESSty не поддерживает циклических связей

С помощью атрибутов-указателей не сложно организовать циклические связи между
объектами. Но текущая версия ObjESSty не поддерживает структур с циклическими
связями. При попытке сериализовать такую структуру ObjESSty не сможет даже
продиагностировать наличие циклической связи. Сериализация ошибки не вызовет,
каждый объект в структуре будет сериализован всего один раз. Но, естественно,
после десериализации исходная информация о ссылках будет потеряна. Более того,
сейчас ObjESSty даже не гарантирует, что атрибуты-указатели после
десериализации будут содержать корректные значения и даже, что сама
десериализация будет завершена успешно.

ObjESSty преднамерено не поддерживает (пока) работу с циклическими
структурами, т.к. наличие циклических ссылок требует двухшаговых операций
сериализации и десериализации. Это означает как усложнение алгоритма
сериализации/десериализации, так и существенное увеличение времени выполнения
данных операций. Кроме того, ситуация усложняется еще и тем, что в ObjESSty
существуют механизмы расширяемых типов и неизвестных расширений. Пока не
понятно как поступать в случае, если сериализованная на одной стороне
циклическая структура не сможет быть полностью десериализованной на другой
стороне, т.к. вторая сторона использует более старую схему данных и часть
объектов ей просто недоступны, т.к. находятся в неизвестном расширении.

Диагностирование попытки сериализации циклической структуры пока так же
затруднена тем, что из-за поддержки множественного и виртуального множественного
наследования вполне легальными являются ситуации, когда некоторая базовая
составляющая сохраняемого типа задействуется при
сериализации/десериализации несколько раз. Например:
\verbatim
{type A ... }
{type B {super {virtual} A } ...}
{type C {super {virtual} C } ...}
{type D {super B} {super C} ...}
\endverbatim
При сериализации объекта типа D сериализация атрибутов базовой составляющей
D::A будет задействована дважды: один раз через D::B::A, второй раз через
D::C::A. Но в образе D должна быть только одна копия атрибутов D::A. Поэтому
вспомогательный код ObjESSty контролирует повторную сериализацию/десериализацию
одного и того же объекта (в данном случае таким объектом является составляющая
D::A) в рамках одной операции. Но при работе с циклическими структурами
вспомогательный код ObjESSty не может отличить повторную
сериализацию/десериализацию, которая вызвана множественным наследованием от
сериализации/десериализации вызванной циклическими ссылками.

\subsection oess_1__pointer_attr__dangers__dynamic_allocation ObjESSty создает объекты через new

При десериализации ObjESSty создает объекты динамически, с использованием
оператора new. Это означает, что созданные ObjESSty объекты должны быть удалены.
Ответственность за это несет прикладной программист. Если динамически
созданные ObjESSty объекты удалены не будут, то это приведет к расходу
памяти.

Лучше всего всегда хранить в атрибутах-указателях указатели на
динамически созданные объекты. Тогда в деструкторе сериализуемого типа можно
смело вызывать для них delete.

\subsection oess_1__pointer_attr__dangers__lost_pointers Потерянные указатели

При десериализации ObjESSty не контролирует текущее значение атрибута-указателя
-- ему просто присваивается новое значение. Что может привести к потере
указателей и утечке памяти. Для предотвращения этого можно воспользоваться
одним из следующих способов:
- переопределить метод oess_1::stdsn::serializable_t::oess_pre_unpack() и
удалить в нем все объекты, на которые сейчас указывают атрибуты-указатели.
Этот способ работает как для атрибутов, которые описыватся в DDL с помощью
тега <i>{ptr}</i>, так и для атрибутов, которые описываются в DDL с
помощью тега <i>{extension_of}</i>;
- воспользоваться готовым сериализуемым классом умного указателя
oess_1::stdsn::shptr_t. Но shptr_t может заменить только атрибуты, которые
описывались в DDL с помощью <i>{ptr}</i>. Подробнее см.  \ref stdsn_shptr.

\subsection oess_1__pointer_attr__dangers__scheme_mismatch	Несовпадение схем данных

Предположим, что есть приложение 1, у которого в схеме данных определены
типы B, C, D, производные от A. Есть так же приложение 2, которое про тип D
ничего не знает. Если приложение 1 сериализует через указатель на A объект
типа D, то приложение 2 не сможет выполнить десериализацию, т.к. они не
знает про тип D.

Если такие случаи возможны, то следует воспользоваться механизмом
subclassing by extension: \ref oess_1_2_0__subclassing_by_extension.

*/

