1

It may be a easy problem...

the method read in stdin or file read in text has been proved be right. Things go wrong in binary read.

Here I have a class named Laptop and a file named laptop.txt, which is written by the code followed. I have reloaded the >> and <<

using namespace std;

class Laptop
{
private:
    string brand;
    string cpu;
    string ram;
    string disk;
    int reserve;

public:
    Laptop() {}
    Laptop(string aBrand, string aCpu, string aRam, string aDisk, int aReserve)
    {
        this->brand = aBrand;
        this->cpu = aCpu;
        this->ram = aRam;
        this->disk = aDisk;
        this->reserve = aReserve;
    }
    friend ostream &operator<<(ostream &os, const Laptop &laptop)
    {
        os << laptop.brand << " " << laptop.cpu
           << " " << laptop.ram << " " << laptop.disk << " " << laptop.reserve;
        return os;
    }
    friend istream &operator>>(istream &is, Laptop &laptop)
    {
        is >> laptop.brand >> laptop.cpu >> laptop.ram >> laptop.disk >> laptop.reserve;
        return is;
    }
};
int main()
{
    fstream file("laptop.txt", ios::out | ios::binary);

    vector<Laptop> laptops;
    Laptop aLaptop;
    for (int i = 0; i < 5; i++)
    {
        cin >> aLaptop;
        laptops.push_back(aLaptop);
    }
    for (vector<Laptop>::iterator i = laptops.begin(); i != laptops.end(); i++)
    {
        file.write((char *)(&i), sizeof(*i));
    }

    return 0;
}

But things doesn't go right in binary read. Here comes to the exception from class Laptop when I try to push aLaptop to the vector. I really don't know why. It's horrible.

int main()
{
    fstream file("laptop.txt", ios::in);

    vector<Laptop> laptops;
    Laptop aLaptop;

    while (file.peek() != EOF)
    {
        file.read((char *)(&aLaptop), sizeof(aLaptop));
        laptops.push_back(aLaptop);
    }
    return 0;
}

enter image description here

milo
  • 13
  • 2
  • I guess a binary read/write of a class object that contains non-trivial members (like std::string) isn't as simple as you think. How does your read operation know (in advance) how big a particular string member's data is going to be? And where will it put that data? – Adrian Mole Jun 01 '21 at 10:23
  • For an 'overview' of class serialization, [see here](https://stackoverflow.com/q/234724/10871073) [or here](https://stackoverflow.com/q/523872/10871073). – Adrian Mole Jun 01 '21 at 10:27

1 Answers1

0

You have a class consisting of four strings and an int, and you cast a pointer to it to a character pointer and try to read it in binary mode from a text file.

A string consists of a length and a pointer. The pointer is pointing to a variable-sized block of memory containing characters. sizeof returns the size of the length and the pointer, but not the block of characters. So when you read the file, you get the length and the pointer, but not the characters that compose the string. The pointer is thus pointing to garbage.

The correct way to do this is either:

  1. If you know that the string will never contain a null character, read characters, appending them to the string, until you get a null character or the end of file.
  2. Read the length of the string, then read that many characters. If you hit the end of file in the middle of this, throw. You will also need a function to write the string in the same way.

Reading an integer from a binary file works, as long as the integer was written binarily. For portability, it's better to read and write integers in a consistent endianness.

Pierre Abbat
  • 485
  • 4
  • 10