Я пытаюсь сохранить объекты, включая векторы объектов, в двоичном файле.
Вот немного загрузки из файла кода:
template <class T> void read(T* obj,std::ifstream * file) {
file->read((char*)(obj),sizeof(*obj));
file->seekg(int(file->tellg())+sizeof(*obj));
}
void read_db(DB* obj,std::ifstream * file) {
read<DB>(obj,file);
for(int index = 0;index < obj->Arrays.size();index++) {
std::cin.get(); //debugging
obj->Arrays[0].Name = "hi"; //debugging
std::cin.get(); //debugging
std::cout << obj->Arrays[0].Name;
read<DB_ARRAY>(&obj->Arrays[index],file);
for(int row_index = 0;row_index < obj->Arrays[index].Rows.size();row_index++) {
read<DB_ROW>(&obj->Arrays[index].Rows[row_index],file);
for(int int_index = 0;int_index < obj->Arrays[index].Rows[row_index].i_Values.size();int_index++) {
read<DB_VALUE<int>>(&obj->Arrays[index].Rows[row_index].i_Values[int_index],file);
}
}
}
}
А вот и классы DB / DB_ARRAY
class DB {
public:
std::string Name;
std::vector<DB_ARRAY> Arrays;
DB_ARRAY * operator[](std::string);
DB_ARRAY * Create(std::string);
};
class DB_ARRAY {
public:
DB* Parent;
std::string Name;
std::vector<DB_ROW> Rows;
DB_ROW * operator[](int);
DB_ROW * Create();
DB_ARRAY(DB*,std::string);
DB_ARRAY();
};
Так что теперь первый аргумент функции read_db будет иметь правильные значения, а векторный массив Arrays для объекта будет иметь правильный размер. Однако, если я индексирую любое значение любого объекта из obj-> Arrays, это вызовет исключение нарушения доступа.
std::cout << obj->Arrays[0].Name; // error
std::cout << &obj->Arrays[0]; // no error
Последний всегда печатает один и тот же адрес, поэтому, когда я сохраняю объект, приведенный к типу char *, он тоже сохраняет его адрес?
Как указывали различные комментаторы, вы не можете просто сериализовать (не POD) объект, сохранив / восстановив его память.
Обычный способ реализации сериализации — реализовать интерфейс сериализации на классах. Что-то вроде этого:
struct ISerializable {
virtual std::ostream& save(std::ostream& os) const = 0;
virtual std::istream& load(std::istream& is) = 0;
};
Затем вы реализуете этот интерфейс в ваших сериализуемых классах, рекурсивно вызывая save
а также load
на любых членах, ссылающихся на другие сериализуемые классы, и выписывающих любых членов POD. Например.:
class DB_ARRAY : public ISerializable {
public:
DB* Parent;
std::string Name;
std::vector<DB_ROW> Rows;
DB_ROW * operator[](int);
DB_ROW * Create();
DB_ARRAY(DB*,std::string);
DB_ARRAY();
virtual std::ostream& save(std::ostream& os) const
{
// serialize out members
return os;
}
virtual std::istream& load(std::istream& is)
{
// unserialize members
return os;
}
};
Как count0 указал, повышение :: сериализации это также отличная отправная точка.
Каков формат двоичных данных в файле? Пока вы не укажете
что мы не можем сказать вам, как это написать. В основном, вы должны указать
формат для всех ваших типов данных (кроме char
), затем напишите код
записать этот формат, побайтово (или сгенерировать его в буфер);
и с другой стороны, чтобы прочитать его побайтово и восстановить его.
Стандарт C ++ ничего не говорит (или очень мало) о размере и
представление типов данных, Кроме тот sizeof(char)
должно быть
1, и это unsigned char
должно быть чисто двоичное представление над
все биты. И на машинах у меня есть доступ сегодня (Sun Sparc и
ПК), только типы символов имеют общее представление. Что касается
чем более сложные типы, тем память используется в представлении значения
может даже не быть смежным: побитовое представление
std::vector
Например, обычно это три указателя, причем
Значения в векторе находятся где-то еще полностью.
Функции istream::read
а также ostream::write
являются
предназначен для чтения данных в буфер для ручного анализа и записи
предварительно отформатированный буфер. Тот факт, что вам нужно использовать
reinterpret_cast
использовать их иначе должно быть хорошим показателем
что это не сработает.