Во-первых: используйте std :: string в своем классе, в долгосрочной перспективе это сделает вашу жизнь намного проще.
Но этот совет работает как для std :: string, так и для char * (с небольшими изменениями, которыедолжно быть очевидно).
В основном вы хотите сериализовать данные неизвестного размера (во время компиляции).Это означает, что когда вы десериализуете данные, у вас должен быть либо метод, который сообщает вам, как долго эти данные (префикс объекта с размером), либо способ найти конец данных (маркер завершения).
Маркер завершения легче для сериализации.Но сложнее для десериализации (как вы должны стремиться, чтобы найти конец).Также вы должны избегать любых вхождений маркера завершения в вашем объекте, а десериализация должна знать об экранировании и удалять его.
Таким образом, из-за этих сложностей я предпочитаю не использовать маркер завершения.В результате я префикс объекта с размером.Плата за это заключается в том, что я должен кодировать размер объекта таким образом, чтобы он не ломался.
Поэтому, если мы добавим префикс объекта с его размером, вы можете сделать это:
// Place a ':' between the string and the size.
// There must be a marker as >> will continue reading if
// fname contains a digit as its first character.
// I don;t like using a space as >> skips spaces if you are not carefull
// and it is hard to tell the start of the string if the first characters in fname
// are the space character.
std::cout << strlen(fname) << ":" << fname;
Затем вы можете десериализоваться следующим образом:
size_t size;
char mark;
std::cint >> size >> mark;
if (!std::cin || mark != ':')
{ throw BadDataException;
}
result = new char[size+1](); // Note the () to zero fill the array.
std::cin.read(result, size)
Редактировать 1 (на основе комментариев) Обновление: использовать со строкой:
size_t size;
char mark;
std::cint >> size >> mark;
if (!std::cin || mark != ':')
{ throw BadDataException;
}
std::string result(' ', size); // Initialize string with enough space.
std::cin.read(&result[0], size) // Just read directly into the string
Редактировать 2 (на основе комментариев)
Вспомогательная функция для сериализации строки
struct StringSerializer
{
std::string& value;
StringSerializer(std::string const& v):value(const_cast<std::string&>(v)){}
friend std::ostream& operator<<(std::ostream& stream, StringSerializer const& data)
{
stream << data.value.size() << ':' << data.value;
}
friend std::istream& operator>>(std::istream& stream, StringSerializer const& data)
{
std::size_t size;
char mark(' ');
stream >> size >> mark;
if (!stream || mark != ':')
{ stream.setstate(std::ios::badbit);
return stream;
}
data.value.resize(size);
stream.read(&data.value[0], size);
}
};
Сериализация лица
std::ostream& operator<<(std::ostream& stream, Person const& data)
{
return stream << StringSerializer(data.fname) << " "
<< StringSerializer(data.lname) << " "
<< data.age << "\n";
}
std::istream& operator>>(std::istream& stream, Person& data)
{
stream >> StringSerializer(data.fname)
>> StringSerializer(data.lname)
>> data.age;
std::string line;
std::getline(stream, line);
if (!line.empty())
{ stream.setstate(std::ios::badbit);
}
return stream;
}
Использование:
int main()
{
Person p;
std::cin >> p;
std::cout << p;
std::ofstream f("data");
f << p;
}