Запись объекта класса в файл

199
20 апреля 2018, 15:52

Прочитал это: Запись string в бинарый файл . С++

Поясняю - открываю отдельный вопрос, потому что репутации не хватает на комменты 8(

Респект Harry - смотрю, часто отвечает. Плиз, поясните, а почему вообще возникает проблема со считыванием полей класса string? Подозреваю, из-за непредсказуемой длины строк, но хотелось бы знать точно.

Именно поэтому Harry советует записывать предварительно длину в инт/переменную и считывать каждое поле класса отдельно?

И еще одно уточнение - значит, методы write/read из библиотек fstream'а можно использовать только для классов со стандартными полями (типа int, double) а для string и char* нужно писать переопределённые методы/друж-функции?

Answer 1

Давайте рассмотрим, что такое класс string, но в пока в идеализированном состоянии. Это просто структура, которая хранит размер строки, указатель на нее и емкость строки (то есть, реальный размер буфера, на который указывает строка).

В этот момент уже должно быть тревожно - там есть указатель! И сохраняя просто переменную типа string в файл как структуру (а ее размер оказывается обычно 32 байта), мы сохраняем размер, емкость (capacity) и указатель. После перезапуска программы этот указатель будет показывать в пустоту или куда то, где об этом не будут знать.

Почему так? да просто при подобном сохранении сохраняются только байты, они не знают о внутренней логике программы.

Почему иногда это все таки работает, не смотря на указатель? Во первых, часто тестируют не закрывая программу. В этом случае есть большая вероятность (ещё раз - гарантий нет, а только вероятность), что данные по указателю не будут испорчены.

Во вторых, есть такая штука, как SSO - small string optimization - оптимизация маленьких строк. Если строка небольшого размера (5-10 символов), то ее можно вместить прямо внутри структуры там, где хранится указатель-емкость. В теории можно запихнуть до 31 байта (если вся структура 32 байта - один битик нужен как флажок). И вот такая строка должна сохраниться и восстановится нормально - у нее нет "внешних буферов".

Теперь перейдем ближе к вопросу. Так как размер string в байтах не меняется (а иначе было бы невозможно объявить переменную класса типа string - компилятор бы не знал, сколько памяти выделять), то и при десериализации нужно знать размер строки, чтобы знать, сколько читать.

методы write/read из библиотек fstream'а можно использовать только для классов со стандартными полями (типа int, double) а для string и char* нужно писать переопределённые методы/друж-функции?

этими функциями можно писать pod типы. А string таким не является. (точнее, он иногда может быть таким - sso). По другому - если переменные класса не являются явными или неявными указателями (класс/структура имеет внешние данные), то для такого типа нужно писать специализированный сериализатор/десериализатор).

READ ALSO
function return promise

function return promise

Что вернёт функция, промис или строку?

225
Правильная реализация MVC на ES6?

Правильная реализация MVC на ES6?

Добрый день! Не могу понять, как правильно реализовать MVC паттерн, вот пример кода:

243
Как создать таймер для пользователя?

Как создать таймер для пользователя?

У меня бот для вкМне нужно что бы при вводе команды test бот ответил пользователю "Работаю"

175
Как поставить на img эффект tooltip . wordpress?

Как поставить на img эффект tooltip . wordpress?

Как поставить эффект tooltip js на img , проект на wordpress

227