Re: сериализация - создание при чтении
От: Sergey Россия  
Дата: 11.10.06 07:35
Оценка: 2 (1)
> Давно мучает вопрос, не могу найти элегантного решения.

Язык какой? Элегантность/не элегантность часто зависит от средств, которыми допустимо пользоваться.

> Есть несколько классов с общим предком. В хранилище есть объект одного из этих классов (неизвестно, какого именно). Необходимо загрузить данные из файла.

>
> Создать объект и вызвать у него .load() нельзя, т.к. неизвестен его тип. Получается, что нужно сначала прочитать тип, а потом создать объект и тогда уже загрузить его данные. Тогда получается, нужно создать объекта-хозяина, который этим будет заниматься (хранить указатель, читать тип, создавать объект, вызывать его загрузку, уничтожать и т.д.).

Ну фабрика для создания объектов потребуется в любом случае (желательно, встроенная в язык ). А вот объект-хозяин — не обязательно.

> Тогда получается, что и сохранять такой объект нужно методом того же хозяина, который будет сохранять тип, потом сохранять объект.

>
> Вопрос в чем: все ли здесь верно с точки зрения построения архитектуры?

Недостаточно гибкая архитектура, на мой взгляд. Зачем объект-хозяин должен хранить указатель на созданный объект и заниматься уничтожением объекта? Ведь ты грузишь объект куда-то — вот там, куда загрузил, его можно и уничтожать впоследствии.

> Как решаются такие вопросы в системах сериализации?


Скажем, в boost::serialization данная задача решена так:
Есть глобальная фабрика, умеющая по некоему описателю типа создавать объект (описатель типа тоже является сериализуемым объектом). Есть классы архивов, отдельно input_archive, отдельно output_archive, умеющие читать-писать объекты. Сериализуемый тип предоставляет некий интерфейс для сериализации, о котором знает архив (перегруженные функции serialize для встроенных типов и классов или функции-члены serialize для классов). Объект сохраняется вызовом метода архива (операторы <<, >> или &). Архив при необходимости (если класс сериализуется полиморфно) регистрирует класс в фабрике и записывает/читает в стрим сначала описатель типа (и версию, кстати), потом данные класса. На время загрузки созданными объектами владеет архив (чтобы прибить их в случае возникновения исключений), потом владение передается тому коду, который и вызвал сериализацию. Архив так же отвечает за то, в каком формате писать данные в стрим — просто есть несколько пар архивов, для бинарной, текстовой, xml сериализации.
Posted via RSDN NNTP Server 2.0
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[3]: сериализация - создание при чтении
От: Sergey Россия  
Дата: 12.10.06 08:22
Оценка: 2 (1)
>S>Язык какой? Элегантность/не элегантность часто зависит от средств, которыми допустимо пользоваться.
>
> C++
>
> S>Ну фабрика для создания объектов потребуется в любом случае (желательно, встроенная в язык ). А вот объект-хозяин — не обязательно.
>
> Вопрос тогда такой: кто должен заниматься чтением/записью типа объекта в/из контейнер(а)?

Все точно так же, как и при сериализации любого другого объекта. Код из буста выглядит так:


template<class Archive, class Container>
struct archive_input_seq
{
inline void operator()(Archive &ar, Container &s)
{
detail::stack_construct<Archive, BOOST_DEDUCED_TYPENAME Container::value_type> t(ar);
// borland fails silently w/o full namespace
ar >> boost::serialization::make_nvp("item", t.reference());
s.push_back(t.reference());
ar.reset_object_address(& s.back() , & t.reference());
}
};
template<class Archive, class U, class Allocator>
inline void load(
Archive & ar,
STD::vector<U, Allocator> &t,
const unsigned int /* file_version */
){
boost::serialization::stl::load_collection<
Archive,
STD::vector<U, Allocator>,
boost::serialization::stl::archive_input_seq<
Archive, STD::vector<U, Allocator> 
>,
boost::serialization::stl::reserve_imp<STD::vector<U, Allocator> >
>(ar, t);
}


Если повыкидывать несущественные для понимания сути подробности и тонкости, то останется примерно следующее:
template<class Archive, class U, class Allocator>
inline void load(Archive & ar, STD::vector<U, Allocator> &t, const unsigned int /* file_version */)
{
    std::size_t count;
    ar >> count;
    t.reserve(count);
    while (count--)
    {
        U v;
        ar >> boost::serialization::make_nvp("item", v);
        t.push_back(v);
    }
}


>

> S>Недостаточно гибкая архитектура, на мой взгляд. Зачем объект-хозяин должен хранить указатель на созданный объект и заниматься уничтожением объекта? Ведь ты грузишь объект куда-то — вот там, куда загрузил, его можно и уничтожать впоследствии.
>
> Предполагалось, что хозяин полностью владеет объектом и уничтожает его в своем деструкторе. Создает же объект в методе загрузки, после чтения идентификатора типа. Муть?

Просто неудобно. Допустим, у меня в программе где-то в качестве члена класса используется std::vector<boost::shared_ptr<MyClass> >; Фактически, после загрузки его из файла вашим способом я буду вынужден скопировать его из "объекта-хозяина сериализации" в тот объект, которому он реально нужен, а потом попросить "объект-хозяина сериализации" уничтожить старую копию — поскольку она больше не нужна. Зачем это писать каждый раз, когда это вполне разумное действие можно сделать дефолтным?

> Не понятно, как идеологически правильно: можно сделать, чтобы архив умел сохранять объекты в нужный формат, тогда нужно учить архив работать с разными типами объектов. Можно сделать, чтобы объекты сами умели сохраняться в архив, тогда нужно делать, чтобы они умели сохраняться в архивы разных типов. Кто должен владеть этим кодом?


Архивы умеют сохранять только примитивные типы, а сами объекты либо умеют сохраняться в любой из архивов, предоставляя шаблонные функции save/load/serialize, либо умеют сериализоваться в конкретный тип архива (а им может быть, например, polymorphic_iarchive/polymorphic_oarchive, от которых унаследованы polymorphic_binary_iarchive, polymorphic_text_iarchive, polymorphic_xml_iarchive). Вообще, лучше доку соответствующую посмотрите — там все понятно написано.
Posted via RSDN NNTP Server 2.0
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
сериализация - создание при чтении
От: Pavel Anufrikov Россия  
Дата: 11.10.06 06:31
Оценка:
Давно мучает вопрос, не могу найти элегантного решения.

Есть несколько классов с общим предком. В хранилище есть объект одного из этих классов (неизвестно, какого именно). Необходимо загрузить данные из файла.

Создать объект и вызвать у него .load() нельзя, т.к. неизвестен его тип. Получается, что нужно сначала прочитать тип, а потом создать объект и тогда уже загрузить его данные. Тогда получается, нужно создать объекта-хозяина, который этим будет заниматься (хранить указатель, читать тип, создавать объект, вызывать его загрузку, уничтожать и т.д.). Тогда получается, что и сохранять такой объект нужно методом того же хозяина, который будет сохранять тип, потом сохранять объект.

Вопрос в чем: все ли здесь верно с точки зрения построения архитектуры? Как решаются такие вопросы в системах сериализации?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: сериализация - создание при чтении
От: Gangsta  
Дата: 11.10.06 14:20
Оценка:
Здравствуйте, Pavel Anufrikov, Вы писали:

PA>Есть несколько классов с общим предком. В хранилище есть объект одного из этих классов (неизвестно, какого именно). Необходимо загрузить данные из файла.


PA>Создать объект и вызвать у него .load() нельзя, т.к. неизвестен его тип.


А почему нельзя создать один класс, от которого унаследовать все твои классы. Подклассы будут переопределять метод load — вот и все. Подробнее см. паттерн "Шаблонный метод".
Re[2]: сериализация - создание при чтении
От: Pavel Anufrikov Россия  
Дата: 12.10.06 04:16
Оценка:
Здравствуйте, Gangsta, Вы писали:

G>А почему нельзя создать один класс, от которого унаследовать все твои классы. Подклассы будут переопределять метод load — вот и все. Подробнее см. паттерн "Шаблонный метод".


Не совсем понял. У них один предок, только при загрузке тип объекта еще не известен. Вопрос как раз в том, кто должен владеть таким объектом, читать его тип, создавать, вызывать его загрузку.
Re[2]: сериализация - создание при чтении
От: Pavel Anufrikov Россия  
Дата: 12.10.06 04:17
Оценка:
S>Язык какой? Элегантность/не элегантность часто зависит от средств, которыми допустимо пользоваться.

C++

S>Ну фабрика для создания объектов потребуется в любом случае (желательно, встроенная в язык ). А вот объект-хозяин — не обязательно.


Вопрос тогда такой: кто должен заниматься чтением/записью типа объекта в/из контейнер(а)?

S>Недостаточно гибкая архитектура, на мой взгляд. Зачем объект-хозяин должен хранить указатель на созданный объект и заниматься уничтожением объекта? Ведь ты грузишь объект куда-то — вот там, куда загрузил, его можно и уничтожать впоследствии.


Предполагалось, что хозяин полностью владеет объектом и уничтожает его в своем деструкторе. Создает же объект в методе загрузки, после чтения идентификатора типа. Муть?

S>Скажем, в boost::serialization данная задача решена так:

S>Есть глобальная фабрика, умеющая по некоему описателю типа создавать объект (описатель типа тоже является сериализуемым объектом). Есть классы архивов, отдельно input_archive, отдельно output_archive, умеющие читать-писать объекты. Сериализуемый тип предоставляет некий интерфейс для сериализации, о котором знает архив (перегруженные функции serialize для встроенных типов и классов или функции-члены serialize для классов). Объект сохраняется вызовом метода архива (операторы <<, >> или &). Архив при необходимости (если класс сериализуется полиморфно) регистрирует класс в фабрике и записывает/читает в стрим сначала описатель типа (и версию, кстати), потом данные класса. На время загрузки созданными объектами владеет архив (чтобы прибить их в случае возникновения исключений), потом владение передается тому коду, который и вызвал сериализацию. Архив так же отвечает за то, в каком формате писать данные в стрим — просто есть несколько пар архивов, для бинарной, текстовой, xml сериализации.

Не понятно, как идеологически правильно: можно сделать, чтобы архив умел сохранять объекты в нужный формат, тогда нужно учить архив работать с разными типами объектов. Можно сделать, чтобы объекты сами умели сохраняться в архив, тогда нужно делать, чтобы они умели сохраняться в архивы разных типов. Кто должен владеть этим кодом?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.