Модераторы: Daevaorn
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Serialize/Deserialize, сделать по уму 
:(
    Опции темы
GKosh
Дата 27.12.2005, 09:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 30
Регистрация: 27.12.2005

Репутация: нет
Всего: нет



Необходимо было реализовать сериализацию для иерархии собственных классов, сделал так:
Базовый класс всей иерархии имеет динамический список структур вида

struct PROPERTY {
const char* sProperty; // имя переменной - члена класса
void** pProperty; // указатель на переменную
SERIA_TYPE Type; // метка типа переменной (int, float, string, object)
};

по идее - это как бы карта свойств объекта, базовый класс реализует так же метод:
void Register_Property (const char* a_name, void* a_pointer, SERIA_TYPE a_type)
для заполнения этого списка указателями на переменные.
Каждый класс иерархии в своем конструкторе регистрирует свои переменные этой функцией, после чего наследованные методы базового класса Serialize/Deserialize уже спокойно записывают, считывают заполненный список указателей.
Таким образом практически вся реализация ser/deser находится только в базовом классе.
Вопрос - может быть что-нибудь есть дурного в таком подходе, пока я его еще не отладил но у меня имеются некоторые сомнения в его надежности. Возможно есть проверенные методы о которых я, к сожалению, не в курсе.

Заранее благодарен,
Константин.
PM MAIL   Вверх
Earnest
Дата 27.12.2005, 09:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 53
Всего: 183



Цитата(GKosh @ 27.12.2005, 09:00)
Вопрос - может быть что-нибудь есть дурного в таком подходе

Конечно. Твой подход годится только для очень простых структур (где только независимые переменные). Да и то, а если это не-плоские классы? Или строки (не char[] а string)? Нельзя их тупо по адресу писать-читать. Пардон, строки у тебя предусмотрены... Однако все остальное - в силе. Представь, у тебя есть контейнер, где частью элемента являются ссылки на какие-то другие классы (которые тоже сериализуются).
Но самое главное (ИМХО) - скрытое хранение адресов элементов класса где-то еще лишает его объекты семантики значений - или нужно потратить усилия, чтобы ее обеспечить. Неоправданное усложнение, по-моему.

Сама по себе сериализация становится сложной, только когда начинаешь думать о поддержке версий. А так - чем проще, тем лучше.

Мне кажется, в данном случае лучше подходить проще: сделать в базовом классе твоей иерархии метод Serialize (как в MFC) и переопределять его + написать хелперы для сериализации контейнеров, строк и простых типов. Здесь по крайней мере соблюдается единство места: все поведение класса локализовано и все изменения производятся в одном месте.
Вроде есть еще boost::seriazlize, но сама не пользовалась.



--------------------
...
PM   Вверх
azesmcar
Дата 27.12.2005, 09:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


uploading...
****


Профиль
Группа: Участник Клуба
Сообщений: 6291
Регистрация: 12.11.2004
Где: Армения

Репутация: 81
Всего: 211



Цитата
Мне кажется, в данном случае лучше подходить проще: сделать в базовом классе твоей иерархии метод Serialize (как в MFC) и переопределять его + написать хелперы для сериализации контейнеров, строк и простых типов. Здесь по крайней мере соблюдается единство места: все поведение класса локализовано и все изменения производятся в одном месте.


Немало думал над этим, пока что (во всяком случае для меня) единственный приемлемый вариант был такой...это для серилизации некоторых структур...например есть функция которая должна записывать структуры и классы в файл...
Код

void WriteToFileStruct(...);

Реализуем класс наподобие...
Код

class CSerilizibleClass
{
public:
   void Serilize(char *pBuffer, int& nBufferSizeRef) = 0;
   void Unserilize(const char *pBuffer, int nBufferSize) = 0;
};

А функцуя WriteToFileStruct будет иметь следующий вид
Код

void WriteToFileStruct(CSerilizibleClass* pClass)
{
   pClass->Serilize(...);
   //...
}

Ничего более универсального придумать не смог...да вряд ли есть способ..если в классе есть динамическое выделение памяти
PM   Вверх
Chaos A.D.
Дата 27.12.2005, 11:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 172
Регистрация: 16.1.2005
Где: 09 RUS

Репутация: 6
Всего: 7



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

И не стоит заморачиваться с решением общего случая сериализации - лучше чем у Boost-а вряд-ли получится. В любом случае, у тебя в твоем примере каждый производный класс должен знать о том, что его будут сериализовать (я имею ввиду твой конструктор). Ну а так, перегружаешь функцию, и все. Если напрягает то, что класс должен знать о том, куда его пишут, сделай функцию, которая бы просто преобразовала объект в последовательность битов, и наоборот. А всё остальное выноси из класса.

Можно так-же заюзать паттерн Factory, производящий объекты из строки. Страуструп в своей книге пару раз упомянает объектный ввод/вывод - Тоже интересная идея - делаешь конструктор, создающий объект из потока ввода. И потом просто читаешь файл: при прочтении строки, которая сопоставлена с определенной make-функцией, вызываешь её, а она, в свою очередь, вызывает конструктор с твоим файлом.
Ну а вообще, я бы заюзал boost::serialize. В нем, как говорится, All Included. Самое приятное, что boost::serialize не интрузивен, т.е. твои классы вообще не должны ничего на себя брать.

Это сообщение отредактировал(а) Chaos A.D. - 27.12.2005, 11:38
--------------------
Надо смеяться над тем, что тебя мучит, иначе не сохранишь равновесия, иначе мир сведет тебя с ума...Ken Kesey - One Flew Over The Cocoo's Nest
PM MAIL   Вверх
Earnest
Дата 27.12.2005, 12:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 53
Всего: 183



Цитата(Chaos @ 27.12.2005, 11:31)
Страуструп в своей книге пару раз упомянает объектный ввод/вывод - Тоже интересная идея - делаешь конструктор, создающий объект из потока ввода

Интересная, но не симметричная - куда запись запихать? Приходится делать функцию Save, а тогда уж логичнее Load для симметрии. Правда, ее (Load) можно вызывать и из конструктора, чтобы можно было писать CMyObject Obj(in); - что, действительно, иногда удобно.

Добавлено @ 12:54
Цитата(Chaos @ 27.12.2005, 11:31)
сделай функцию, которая бы просто преобразовала объект в последовательность битов, и наоборот.

Лучше (в С++) в базовый поток (istream).



--------------------
...
PM   Вверх
Chaos A.D.
Дата 27.12.2005, 14:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 172
Регистрация: 16.1.2005
Где: 09 RUS

Репутация: 6
Всего: 7



Цитата(Earnest @ 27.12.2005, 12:53)
Интересная, но не симметричная...

Мне почему-то вспомнился отрывок из книги Джеффа Элджера C++ For Real Programmers...
Цитата

... А пока скажите начальнику и коллегам, что уничтожающие функции нужны вам ради симметрии. Они косо посмотрят на вас и отойдут подальше, так что на какое-то время вам будет спокойнее работать.

smile

Это сообщение отредактировал(а) Chaos A.D. - 27.12.2005, 14:04
--------------------
Надо смеяться над тем, что тебя мучит, иначе не сохранишь равновесия, иначе мир сведет тебя с ума...Ken Kesey - One Flew Over The Cocoo's Nest
PM MAIL   Вверх
Earnest
Дата 27.12.2005, 15:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 53
Всего: 183



Не читала... smile
Но книжка, наверное, хорошая.
А вообще, разве ты не чувствуешь, что симметричный код, как-то... более соответствует мировой гармонии? smile



--------------------
...
PM   Вверх
Chaos A.D.
Дата 27.12.2005, 16:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 172
Регистрация: 16.1.2005
Где: 09 RUS

Репутация: 6
Всего: 7



Цитата(Earnest @ 27.12.2005, 15:22)
Не читала... 
Но книжка, наверное, хорошая.
А вообще, разве ты не чувствуешь, что симметричный код, как-то... более соответствует мировой гармонии?


Хы, оттуда же цитата, которую я полностью поддерживаю:
Цитата

Вставить PFoo в существующую программу совсем несложно — при условии, что вы приняли все
меры предосторожности, спроектировали его с расчетом на гомоморфную иерархию классов и
инкапсулировали производные классы вроде Bar. Ведь вы это сделали, не правда ли? Перед нами
очередной мистический принцип — вы делаете что-то не для того, чтобы извлечь непосредственную
пользу, а для сохранения мировой гармонии. В один прекрасный день вам потребуется вставить умный
указатель, и в гармоничном мире это не вызовет никаких проблем.

Вообще, я сам люблю, когда все в проекте гармонично. Например, когда я думаю об одном из своих проектов, который мне приходится сопровождать, у меня в голове мигом рисуется схема того, какая часть программы чего использует, как что-к-чему относится и зависит. И у этого проекта архитектура настолько запутанная, что в голове сплошная мешанина. Поэтому, я ничего не имею против красивого и правильного "симметричного" кода. Просто, цитату смешную вспомнил.
--------------------
Надо смеяться над тем, что тебя мучит, иначе не сохранишь равновесия, иначе мир сведет тебя с ума...Ken Kesey - One Flew Over The Cocoo's Nest
PM MAIL   Вверх
Chaos A.D.
Дата 27.12.2005, 16:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 172
Регистрация: 16.1.2005
Где: 09 RUS

Репутация: 6
Всего: 7



А книга есть в электронном формате, но она, как бы вроде для тех, кто только что прочел Страуструпа что-нибудь другое для начинающих. Хотя после Александреску, Саттера и Мейерса перечитывать довольно любопытно. Как-то нестандартно мыслит мужик (хоть и примеры немного надуманные).
--------------------
Надо смеяться над тем, что тебя мучит, иначе не сохранишь равновесия, иначе мир сведет тебя с ума...Ken Kesey - One Flew Over The Cocoo's Nest
PM MAIL   Вверх
GKosh
Дата 31.12.2005, 12:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 30
Регистрация: 27.12.2005

Репутация: нет
Всего: нет



Спасибо всем,
boost::serialize гляну, но в моем случае мне нужен очень четкий контроль за создаваемой структурой.
Сериализоваться будет дерево, с большим числом полиморфных классов внутри. Соответсвенно должна быть возможность:
Код

CMyTree* mytree = new CMyTree(tree.txt);

и этого должно быть достаточно для каскада динамического выделения памяти под все более удаленные от корня объекты - вообщем, наверное лучше писать самому.

Цитата(Earnest @ 27.12.2005, 09:28)
Да и то, а если это не-плоские классы? Или строки

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

struct PROPERTY {
const char* sProperty; // имя переменной - члена класса
void** pProperty; // указатель на переменную
SERIA_TYPE Type; // метка типа переменной (int, float, string, object)
};

Вон тот вот void** мне признаться не нравится - можно было бы как-то иначе указывать на член класса (помним, что членом класса может быть указатель на объект другого класса) без void, но чтобы и на int и на string и на условный CMyTree - полагаю использование полиморфной оболочки на int - это будет перебор.
PM MAIL   Вверх
DeadSoul
Дата 31.12.2005, 13:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник
Сообщений: 1217
Регистрация: 25.9.2005
Где: Москва

Репутация: 2
Всего: 11



Цитата(GKosh @ 27.12.2005, 09:00)
void** pProperty; // указатель на переменную
SERIA_TYPE Type; // метка типа переменной (int, float, string, object)

это нужно заменить на varint\ boost::variant \ boost::any.

После этого смотри как сериализация устроена в бусте или MFC


--------------------
 Если Вы получили ответ на Ваш вопрос, то нажмите на "Вопрос решен". 

Бьем спамеров их же оружием. Пусть весь спам сыпется им
[email protected] 
PM   Вверх
GKosh
Дата 31.12.2005, 16:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 30
Регистрация: 27.12.2005

Репутация: нет
Всего: нет



Цитата(DeadSoul @ 31.12.2005, 13:15)
После этого смотри как сериализация устроена в бусте или MFC

Сериализация boost'а мне не годится, нужно, чтобы сэйв можно было бы при необходимости редактировать или даже составлять от руки - нужен парсер команд, навроде color = 100; m_root += CNode и.т.п. Впрочем не суть. boost::any гляну - это как variant в VBasic'е? Или он хранит информация о своем "настоящем" типе?

PM MAIL   Вверх
Daevaorn
Дата 31.12.2005, 16:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2155
Регистрация: 29.11.2004
Где: Москва

Репутация: 51
Всего: 70



GKosh
Цитата

Или он хранит информация о своем "настоящем" типе?

Там голый void*, но использует RTTI для опредеения текущего типа и конвертации в нужный.
PM MAIL WWW   Вверх
DeadSoul
Дата 31.12.2005, 16:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник
Сообщений: 1217
Регистрация: 25.9.2005
Где: Москва

Репутация: 2
Всего: 11



Цитата(GKosh @ 31.12.2005, 16:20)
Впрочем не суть. boost::any гляну - это как variant в VBasic'е?

нет. При изспользование boost::any клиент олжен знать кто там хранится. Тут может пригодится boost::variant(это не тот вариант о котором ты подумал. Это намного круче)


--------------------
 Если Вы получили ответ на Ваш вопрос, то нажмите на "Вопрос решен". 

Бьем спамеров их же оружием. Пусть весь спам сыпется им
[email protected] 
PM   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.4429 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.