В вашем коде предполагается, что все соответствующие данные существуют непосредственно внутри вектора, тогда как строки представляют собой объекты фиксированного размера, имеющие указатели, которые могут добавлять их содержимое переменного размера в кучу. Вы в основном сохраняете указатели, а не текст. Вы должны написать некоторый код сериализации строки, например:
bool write_string(std::ostream& os, const std::string& s)
{
size_t n = s.size();
return os.write(n, sizeof n) && os.write(s.data(), n);
}
Затем вы можете написать подпрограммы сериализации для вашей структуры. Есть несколько вариантов дизайна:
- многим нравится объявлять типы Binary_IStream / Binary_OStream, которые могут содержать std :: ostream, но будучи отдельным типом, можно использовать для создания отдельного набора подпрограмм сериализации ala:
operator<<(Binary_OStream& os, const Some_Class&);
Или вы можете просто отказаться от обычной потоковой записи при работе с двоичной сериализацией и использовать вместо нее запись вызова функции. Очевидно, что хорошо, чтобы один и тот же код корректно выводил как двоичную сериализацию, так и читабельную для человека сериализацию, поэтому подход, основанный на операторе, привлекателен.
Если вы сериализуете номера, вам необходимо решить, делать ли это в двоичном формате или в формате ASCII. В чисто двоичном формате, где требуется переносимость (даже между 32-битными и 64-битными компиляциями в одной и той же ОС), вам может потребоваться приложить некоторые усилия для кодирования и использования метаданных размера шрифта (например, int32_t или int64_t?) в качестве порядка байтов (например, рассмотрим порядок байтов в сети и ntohl () - функции семейства). С ASCII вы можете избежать некоторых из этих соображений, но это переменная длина и может быть медленнее для записи / чтения. Ниже я произвольно использую ASCII с '|' терминатор для цифр.
bool write_element(std::ostream& os, const element& e)
{
return (os << e.id << '|') && write_string(os, e.test) && (os << e.other << '|');
}
А потом для вашего вектора:
os << elements.size() << '|';
for (std::vector<element>::const_iterator i = elements.begin();
i != elements.end(); ++i)
write_element(os, *i);
Чтобы прочитать это обратно:
std::vector<element> elements;
size_t n;
if (is >> n)
for (int i = 0; i < n; ++i)
{
element e;
if (!read_element(is, e))
return false; // fail
elements.push_back(e);
}
... что нужно ...
bool read_element(std::istream& is, element& e)
{
char c;
return (is >> e.id >> c) && c == '|' &&
read_string(is, e.test) &&
(is >> e.other >> c) && c == '|';
}
... и ...
bool read_string(std::istream& is, std::string& s)
{
size_t n;
char c;
if ((is >> n >> c) && c == '|')
{
s.resize(n);
return is.read(s.data(), n);
}
return false;
}