Прочитал это: Запись string в бинарый файл . С++
Поясняю - открываю отдельный вопрос, потому что репутации не хватает на комменты 8(
Респект Harry - смотрю, часто отвечает. Плиз, поясните, а почему вообще возникает проблема со считыванием полей класса string? Подозреваю, из-за непредсказуемой длины строк, но хотелось бы знать точно.
Именно поэтому Harry советует записывать предварительно длину в инт/переменную и считывать каждое поле класса отдельно?
И еще одно уточнение - значит, методы write/read из библиотек fstream'а можно использовать только для классов со стандартными полями (типа int, double) а для string и char* нужно писать переопределённые методы/друж-функции?
Давайте рассмотрим, что такое класс string, но в пока в идеализированном состоянии. Это просто структура, которая хранит размер строки, указатель на нее и емкость строки (то есть, реальный размер буфера, на который указывает строка).
В этот момент уже должно быть тревожно - там есть указатель! И сохраняя просто переменную типа string в файл как структуру (а ее размер оказывается обычно 32 байта), мы сохраняем размер, емкость (capacity) и указатель. После перезапуска программы этот указатель будет показывать в пустоту или куда то, где об этом не будут знать.
Почему так? да просто при подобном сохранении сохраняются только байты, они не знают о внутренней логике программы.
Почему иногда это все таки работает, не смотря на указатель? Во первых, часто тестируют не закрывая программу. В этом случае есть большая вероятность (ещё раз - гарантий нет, а только вероятность), что данные по указателю не будут испорчены.
Во вторых, есть такая штука, как SSO - small string optimization - оптимизация маленьких строк. Если строка небольшого размера (5-10 символов), то ее можно вместить прямо внутри структуры там, где хранится указатель-емкость. В теории можно запихнуть до 31 байта (если вся структура 32 байта - один битик нужен как флажок). И вот такая строка должна сохраниться и восстановится нормально - у нее нет "внешних буферов".
Теперь перейдем ближе к вопросу. Так как размер string в байтах не меняется (а иначе было бы невозможно объявить переменную класса типа string - компилятор бы не знал, сколько памяти выделять), то и при десериализации нужно знать размер строки, чтобы знать, сколько читать.
методы write/read из библиотек fstream'а можно использовать только для классов со стандартными полями (типа int, double) а для string и char* нужно писать переопределённые методы/друж-функции?
этими функциями можно писать pod типы. А string таким не является. (точнее, он иногда может быть таким - sso). По другому - если переменные класса не являются явными или неявными указателями (класс/структура имеет внешние данные), то для такого типа нужно писать специализированный сериализатор/десериализатор).
Сборка персонального компьютера от Artline: умный выбор для современных пользователей