-1
#include <iostream>
#include <string>
#include <fstream>
using namespace std;

class Person{
    private :
        string name;
        int age;
    public :
        Person(string name, int age){
            this->name = name;
            this->age = age;
        }
        void show(){
            cout << "Name : " + name + "\n" << "Age : " << age << \n####################\n";
        }
        ~Person(){
            cout << "object " + name + " deleted\n";
        }
};

int main(){
    ifstream file("./files/C63.bin", ios::binary | ios::in);
    if (!file.is_open()){
        cout << "Error opening the file..\n";
    } else {
        cout << "successfully opened the file..\nThe contents of the binary file are :\n";
        Person *p;
        while (file.good()){
            file.read((char *)p, sizeof(Person));
            cout << "hi\n";
            p->show();
        }
        file.close();
    }
    return 0;
}

At the code line - "file.read((char *)p, sizeof(Person));", segmentation fault occurs. The binary file exists at the specified location with a few person objects. What could have gone wrong?

Ahmed Shamel
  • 1,982
  • 3
  • 24
  • 58
  • 4
    Your code will not work. You cannot read / write a non-POD type such as `Person` in this fashion. A binary file requires you to be reading / writing POD or `C`-layout compatible types. Your `Person` class contains a `std::string`, so that invalidates your whole approach of reading and writing. – PaulMcKenzie Feb 22 '18 at 18:31
  • In addition `file.read((char *)p, sizeof(Person));` is not going to work, not only because `Person` is non-POD, but for the fundamental reason being that `p` is uninitialized. – PaulMcKenzie Feb 22 '18 at 18:33
  • To prove your code doesn't work -- Make the `name` something very long, like a 100 characters or so. When you write `Person` to a file, when you view the file's contents you will see that `name` is either cut off, or gibberish in the file. So how are you going to turn a cut-off / gibberish name back into the correct name by reading the file in this fashion? You are not magically going to turn garbage / gibberish characters back into a 100 character string. – PaulMcKenzie Feb 22 '18 at 18:40
  • 1
    Second, you are reading `sizeof(Person)` characters -- what is the value of `sizeof(Person)`? It is always the same value, regardless of the number of characters in `name`. I won't give an answer, since there isn't one. You simply can't read / write binary data this way. However, you **can** read up on proper *object serialization*. which is the proper way to handle this type of data. – PaulMcKenzie Feb 22 '18 at 18:43
  • @PaulMcKenzie I get confused over what's POD and not. If I make a simple struct and try std::is_pod_v it says true, then I add a default constructor, and it says false. Reading and writing this struct to a binary file should still work, right? – Zebrafish Feb 22 '18 at 18:58
  • @Zebrafish -- [See this](https://stackoverflow.com/questions/12979529/default-constructors-and-pod). I don't think there is a guarantee that a "simple" default constructor means that the type is still readable/writable in a binary fashion. – PaulMcKenzie Feb 22 '18 at 19:02

1 Answers1

1

You've created a pointer to Person, without initialising it. It's just a pointer pointing to God knows where. So when you try to read from the file to it it tries to access invalid memory, that's the segfault.

That's why you got a segfault, but as PaulMcKenzie points out, reading files like this can only read bytes, you can read one byte, or 16 bytes, but you still couldn't construct a Person object by reading just raw data. Let's just say that you had allocated memory for your Person objects, with either malloc or placement new or something, it's only doing a shallow copy. Classes like std::string have a pointer to data, and you'd only be copying pointers to data, but not the data.

Zebrafish
  • 11,682
  • 3
  • 43
  • 119
  • 3
    Even if the pointer was initialized, that won't help matters due to `Person` containing a `std::string` type. – PaulMcKenzie Feb 22 '18 at 18:34
  • @PaulMcKenzie Yeah that too. – Zebrafish Feb 22 '18 at 18:35
  • The `name` field is variable width. There are to common methods: 1) write the length first, then the text and 2) Write text and end with a sentinel value (like '\0'). The first technique allows for block reading of the text and more efficient allocation of the `string` object. – Thomas Matthews Feb 22 '18 at 21:12