#cpp #vector
Возникла проблема. Я изучил абсолютно все, что смог найти. Я перечитал десятки тем на stacoverflow, как на русскоязычном, так и на англоязычном. Но все, что мне удалось найти либо не работает (по причине отличия моего случае от случая в теме), либо вообще не из той оперы. Позвольте я опишу цель и что я уже предпринимал для ее достижения. Сразу уточню, я не в коем случае не прошу писать за меня код, мне просто нужен совет, направление, как именно реализовать то, что мне нужно (какими методами), а их поиском я займусь сам. Итак, у меня есть класс class Legal { private: std::string name; std::string phone; std::string address; std::string date; std::string ogrn; public: Legal( std::string name = "Название не указано", std::string phone = "Номер не указан", std::string address = "Адрес регистрации не указан", std::string date = "Дата основания не указана", std::string ogrn = "ЕГРН не указан" ) { this->name = name; this->phone = phone; this->address = address; this->date = date; this->ogrn = ogrn; } void setName(std::string& name) { this->name = name; } void setPhone(std::string& phone) { this->phone = phone; } void setAddress(std::string& address) { this->address = address; } void setDate(std::string& date) { this->date = date; } void setOgrn(std::string& ogrn) { this->ogrn = ogrn; } std::string getName() { return name; } }; Далее, я создаю vector vecLegal, и с пользователь может создавать новых "клиентов" заполняя объекты этого класса. В итоге получается вектор этих самых объектов, в которых сохраняется информация о "клиентах". Мне нужно, чтобы по итого работы программы все эти объекты из вектора сохранились в файл (txt, bin - не важно) и потом могли из него считываться. Своеобразная база данных. Я пробовал перегружать оператор <<, но в тех примерах экземпляры класса были типов int и у меня возникали проблемы с string. Я пробовал делаться сериализацию с помощью boost, но в этом я не силен и не понял почему не заработало. Лучшее чего мне удалось достичь, это ofstream out_file("vector.bin", ios::binary | ios::out); out_file.write((const char*)&vecToadd.front(), vecToadd.size()*sizeof(Legal)); Этими строками успешно создается файл vector.bin, но при каких либо попытках его считать в вектор я получал "Ошибка сегментирования(дамп памяти сброшен на диск)". Подскажите пожалуйста, что делаю не так и какие шаги стоит предпринять для решения моей проблемы?
Ответы
Ответ 1
Вы как минимум не читали этот сайт - тут столько раз говорилось о том, как быть с такими не-POD объектами, что лично мне уже набило оскомину... Вашим способом вы записываете не содержимое строк в вашем объекте, а их служебные поля. Строка содержит в себе указатель на выделенную где-то память, в которой содержатся интересующая вас информация. Но вы пытаетесь писать просто эти указатели и другие служебные поля... Получается примерно так - жена говорит собраться в отпуск и в машину в багажник сложить, ну, там, матрас надувной, палатку, мангал и шампуры - ну, в общем, барахло. Вы в багажник кладете бумажки с надписями "Матрас - на антресолях", "Палатка - на балконе" и т.д. Так вот сохраняете в файл... По приезду на место читает - вынимаете из бумажника бумажки с надписями, где что лежит. Но хуже того, что шкаф теперь совсем другой, балкон тоже, так что втык от жены - это примерно и есть результат вот такого хранения и попытку раскрыть палатку, которой нет... Примерный набросок, как бы писал-читал я. Набросок - надо дописать проверки и т.п. Функции могут быть переделаны в операторы вывода, но мне это не кажется лучшим способом... Да, касты к char* я тоже опустил для краткости, сами допишите. Сами функции тоже можно оптимизировать - например, выделять память прямо в строке и читать в нее... void writeStr(const string& s, ostream& f) { int l = s.length(); f.write(&l,sizeof(int)); f.write(s.data(),l); } void readStr(string& s, istream&f) { int l; f.read(&l,sizeof(int)); char * str = new char[l+1]; f.read(str,l); str[l] = 0; s = str; delete[] str; } Потом запись в файл вашего класса выглядит как void writeInf(const Legal&l,ostream&f) { writeStr(l.name,f); writeStr(l.phone,f); ... } Ну, и чтение: void readInf(Legal&l, istream&f) { readStr(l.name,f); readStr(l.phone,f); ... } Примерно так... Update Вот полный пример кода: #include#include #include using namespace std; class Test { public: Test(const char * a = "", const char * b = "", const char * c = "") :a(a),b(b),c(c){} void write(ostream&f) const { writeStr(a,f); writeStr(b,f); writeStr(c,f); } void read(istream&f) { readStr(a,f); readStr(b,f); readStr(c,f); } friend ostream& operator << (ostream&f, const Test&t) { return f << "(" << t.a << "," << t.b << "," << t.c << ")"; } private: string a, b, c; static void writeStr(const string& s, ostream& f) { size_t l = s.length(); f.write((const char*)&l,sizeof(size_t)); f.write(s.data(),l); } static void readStr(string& s, istream&f) { size_t l; f.read((char*)&l,sizeof(size_t)); char * str = new char[l+1]; f.read(str,l); str[l] = 0; s = str; delete[] str; } }; int main(int argc, const char * argv[]) { Test x("x","1","2"), y("y","3","4"); Test u,v; cout << u << "\n" << v << "\n\n"; { ofstream out("data",ios::binary); x.write(out); y.write(out); } { ifstream in("data",ios::binary); u.read(in); v.read(in); } cout << u << "\n" << v << "\n\n"; } Ответ 2
Вам нужно написать для своего класса функцию-член для сериализации объекта в массив байт и комплементарный выгрузке конструктор объекта из этого массива. Массив байт Вы и в файл выгрузите и в коммуникационный канал. Теперь о том, как делать сериализацию объекта Вашего (и любого) класса в массив. 1) Сложные структурные типы выгружаются в массив как последовательность отдельных членов. Если класс является производным или содержит указатели на объекты другого типа, для них пишутся отдельные сериализация и комплементарный конструктор. 2) Целые типы -- при выгрузке никаких int, long и прочего резинового использовать нельзя, только из stdint.h. Собственно, все что уходит за пределы программы, даже в пределах одного компьютера, должно описываться только типами из stdint.h и последовательностями из них. 3) std::строки вы выгружаете в массив в виде паскаль-строк, т.е. каждая строка байт предваряется целым, содержащим ее длину в байтах. Потом, когда вы будете конструировать объект, вы эти числа можете использовать как смещения при работе с указателями. И да, без указателей Вы ничего не сериализуете. По данному вопросу очень полезно почитать стандарт ASN.1 и стандарт на формат IIF.
Комментариев нет:
Отправить комментарий