Возникла проблема. Я изучил абсолютно все, что смог найти. Я перечитал десятки тем на 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, но при каких либо попытках его считать в вектор я получал "Ошибка сегментирования(дамп памяти сброшен на диск)". Подскажите пожалуйста, что делаю не так и какие шаги стоит предпринять для решения моей проблемы?
Вы как минимум не читали этот сайт - тут столько раз говорилось о том, как быть с такими не-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 <string>
#include <iostream>
#include <fstream>
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";
}
Вам нужно написать для своего класса функцию-член для сериализации объекта в массив байт и комплементарный выгрузке конструктор объекта из этого массива. Массив байт Вы и в файл выгрузите и в коммуникационный канал. Теперь о том, как делать сериализацию объекта Вашего (и любого) класса в массив.
1) Сложные структурные типы выгружаются в массив как последовательность отдельных членов. Если класс является производным или содержит указатели на объекты другого типа, для них пишутся отдельные сериализация и комплементарный конструктор.
2) Целые типы -- при выгрузке никаких int, long и прочего резинового использовать нельзя, только из stdint.h. Собственно, все что уходит за пределы программы, даже в пределах одного компьютера, должно описываться только типами из stdint.h и последовательностями из них.
3) std::строки вы выгружаете в массив в виде паскаль-строк, т.е. каждая строка байт предваряется целым, содержащим ее длину в байтах.
Потом, когда вы будете конструировать объект, вы эти числа можете использовать как смещения при работе с указателями. И да, без указателей Вы ничего не сериализуете.
По данному вопросу очень полезно почитать стандарт ASN.1 и стандарт на формат IIF.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Определенное количество кнопок создается с помощью Repeater(ListModel)Как обратится к определенной кнопки и узнать ее параметры(X, Y)? main
Буквально в конце написания проекта столкнулся с такой проблемой, что не могу придумать как посчитать количество файлов в папке, чтобы создать...