Search code examples
c++serializationstructfile-writing

Weird behavior in struct destruction


I am trying to write a struct to a file and read it back. The code to do so is here:

#include <fstream>
#include <iostream>
#include <cstring>

using namespace std;

struct info {
  int id;
  string name;
};

int main(void) {
  info adam;
  adam.id = 50;
  adam.name = "adam";

  ofstream file("student_info.dat", ios::binary);
  file.write((char*)&adam, sizeof(info));
  file.close();

  info student;
  ifstream file2("student_info.dat", ios::binary);
  file2.read((char*)&student, sizeof(student));
  cout << "ID =" << student.id << " Name = " << student.name << endl;

  file2.close();
  return 0;
}

However I get a strange segmentation fault in the end.

The output is :

ID =50 Name = adam
Segmentation fault (core dumped)

On looking at the core dump, I see that there is something weird happening in the destruction of the struct info.

(gdb) bt
#0  0x00007f035330595c in ?? ()
#1  0x00000000004014d8 in info::~info() () at binio.cc:7
#2  0x00000000004013c9 in main () at binio.cc:21

I suspect that something weird is happening in the string destruction but I am not able to figure out the exact problem. Any help will be great.

I am using gcc 8.2.0.


Solution

  • You can't serialize/deserialize like that. On this line here:

    file2.read((char*)&student, sizeof(student));
    

    You're just writing 1:1 over an instance of info, which includes an std::string. Those aren't just arrays of characters - they dynamically allocate their storage on the heap and manage that using pointers. Thus the string becomes invalid if you overwrite it like that, it's undefined behavior because its pointers aren't pointing to a valid place anymore.

    Instead you should save the actual characters, not the string object, and make a new string with that content on load.


    Generally, you can do a copy like that with trivial objects. You can test it like this:

    std::cout << std::is_trivially_copyable<std::string>::value << '\n';