0

Ok so i have this code i just want to write my struct to the file and then read using another variable because i want to return a vector of userRankings when reading.

Here'es my write/read

void IOManager::WriteBin(const string &filename, userRank u1) {

    ofstream fsalida(filename, ios::out | ios::binary); //obrim un archiu per escriure en binari i de tipo append per poder escriure al final i no xafar-ho tot cada cop

    if (fsalida.is_open())
    {
        fsalida.write(reinterpret_cast<char*>(&u1), sizeof(u1));
        fsalida.close();


    }
    else cout << "Unable to open file for writing\n";

}

void IOManager::ReadBin(const string &filename) {



    ifstream fentrada(filename, ios::in | ios::binary); //ate per posarnos al final del archiu i tenir el tamany

    if (fentrada.is_open())
    {   
        userRank tempUser;
        fentrada.read(reinterpret_cast<char*>(&tempUser), sizeof(tempUser));
        fentrada.close();

        cout << sizeof(tempUser) << endl;

    }
    else cout << "Unable to open file for reading\n";   

}

And my userRank:

struct userRank
{
    std::string userName;
    int score;
};

The line that fails is fentrada.read(reinterpret_cast(&tempUser), sizeof(tempUser));

Please help, this seems to work with ints, chars, etc but not with strings and complex types, does anybody know why?

PauBlanes
  • 11
  • 4
  • 2
    Part of the problem is that your `userRank` has a `std::string` in it, which includes heap-allocated memory, which won't be accessible simply by going to the address of an instance of `userRank` – AndyG Jan 04 '17 at 17:55
  • Complex types may have pointers. The address (pointer value) may not be valid the next time the program is loaded. So, don't store pointers in binary files. – Thomas Matthews Jan 04 '17 at 17:57
  • Ah thanks, so the only way would be using an array of chars? – PauBlanes Jan 04 '17 at 17:58
  • A text string is a variable record. You will need to either store the length and the text, or store the text with some sentinal value. If you wish to use binary writing and reading, you may want to use fixed size character arrays to hold the text (also put in a text length field in the structure). – Thomas Matthews Jan 04 '17 at 17:59
  • FYI, you can keep the string class in your structure, but write and read the text using a different algorithm. I recommend this since writing and reading of the structure will occur less frequently than other access to the data. – Thomas Matthews Jan 04 '17 at 18:00
  • Not sure if this qualifies as a dupe so just linking it here: http://stackoverflow.com/questions/7046244/serializing-a-class-which-contains-a-stdstring – NathanOliver Jan 04 '17 at 18:00
  • But if i do sizeof(emptyuserRank) and sizeof(userRankwithvalues) i get 48 both times, does this mean anything? – PauBlanes Jan 04 '17 at 18:03
  • @PauBlanes No because the size of `std::string` does not include the size of the bytes it uses for the string(disregarding small string optimization. – NathanOliver Jan 04 '17 at 18:13

1 Answers1

0

Using reinterpret_cast in that way is dangerous and may break for many reasons. In this particular case, the reason it doesn't work is because struct userRank contains std::string which is not a POD type (plain old data type). That means you can't simply set it's bits and expect to get the right state. std::string contains a pointer to allocated memory. Setting the bits of a std::string doesn't allocate the memory it is expecting to find at that pointer's address.

The quick fix (relatively speaking) is to use std::array instead of std::string to store the userName. The right fix is to write functions that will read/write the structure's state to/from the file member by member.

François Andrieux
  • 28,148
  • 6
  • 56
  • 87
  • than you, I'll use the quick fix, sry guys i'll do it the right way at some point. I used char* instead of string btw. – PauBlanes Jan 04 '17 at 18:08