Как то было несколько раз нужно записывать и считывать данные на диск. Всего Были тройка классов/структур, имеющие списки структур.
Делал просто двумя функциями для чтения и записи:
Запись - в цикле перебирал списки:
fwrite (&arr[i].x , 1 , sizeof(int) , pFile );
fwrite (&arr[i].y , 1 , sizeof(int) , pFile );
fwrite (&arr[i].z , 1 , sizeof(int) , pFile );
+Во вложенном списке такие же команды для списков элементов списков и т.п.
Загрузка - в цикле перебирал списки:
fread(&x, sizeof(float), 1, F);
fread(&y, sizeof(float), 1, F);
fread(&z, sizeof(float), 1, F);
+Во вложенном списке такие же команды для списков элементов списков и т.п.
Вносим изменения в структуры? Вэлкам править функции записи и чтения. При этом они должны быть аналогичными.
В общем запарился я там дэбагить, т.к. всеравно где-то что-то упустишь.
Пришла в голову мысль как-то это автоматизировать. После чего было понаписано кое-чего с макросами, шаблонами для шаблонов (например для std::list) и прочими ужасами.
В результате функция была одна, но своя для каждого класса/структуры - IO(bool IOtype). IOtype значило или запись или чтение.
В результате помимо прочего появился класс, который наследовался для нуждающихся в чтении/записи классов. Править нужно было только одну наследуемую виртуальную функцию и можно было спокойно менять порядок чтений/записи не опасаясь рассогласования. При этом в теле функции было что-то вроде
IO_int(x);
IO_int(y);
IO_int(z);
IO_List(arr);
Которые можно было менять местами не опасаясь, что они запишутся и прочтутся в разной последовательности.
Всё это велосипеды конечно же и как оно относится к сети? Ну это теже данные представленные в виде байтов, так что хоть на диск хоть по сети, хоть в базы данных. Вот.
Но тут меня осенило, что структуру/класс можно представить в виде байт очень просто:
MyClass C1;
char *p = reinterpret_cast<char*>(&C1);
int size = sizeof(C1);
Но были сомнения. И не напрасно. Вся эта сырая память может выглядеть по разному при разных условиях и содержать "мусор". Из за выравниваний, виртуальных классов и вообще стандарт ничего не гарантирует...
Не гарантирует кроме POD'ов, при условии договоренности о выравниваниях.
Wikipedia : |
Простая структура данных (англ. plain old data, POD) — в современных языках программирования высокого уровня тип данных, имеющий жёстко определённое расположение полей в памяти, не требующий ограничения доступа и автоматического управления. Переменные такого типа можно копировать простыми процедурами копирования участков памяти наподобие memcpy.
<...>
В C++ POD определяется от противного. Тип данных является POD’ом, если:
у него нет конструктора, деструктора и копирующей операции присваивания (то есть operator=, принимающего на входе тот же тип);
среди нестатических полей нет ссылок C++, не-POD’ов, private и protected;
нет виртуальных методов;
он ни от чего не унаследован.
По стандарту C++ простой тип данных устроен в точности так, как описано. Управляемую же структуру компилятор может реорганизовать так, как он сочтёт наиболее эффективным.
|
Отлично! Я согласен на небольшой мусор в выравниваниях, лишь бы не мучиться с одельными полями структур.