CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 2 of 3 FirstFirst 123 LastLast
Results 16 to 30 of 34
  1. #16
    Join Date
    Apr 1999
    Posts
    27,449

    Re: Save/load functions not working

    Quote Originally Posted by KruSuPhy View Post
    I was merely asking if there is a method similar to that pseudo-code,
    How is a general method going to know what your object consists of? You still have to write the code to output the contents to a file, and write the code to read the file. There are no shortcuts.

    The question really should be how you do this. In C++, you could overload the streaming operators (operator << for output and operator >> for input) for the class.

    One thing I don't recommend is that "LoadGame()" pseudo-code you have. You shouldn't mix error handling with file reading logic in the same function. What if you want to read the file, and if it doesn't exist, output an error to a log file, or read from an alternate file, or any number of other things? The LoadGame() should just return an error or throw an exception if the file doesn't exist and not do anything else. Then the caller decides what to do instead of LoadGame() controlling what is done.

    However did you do as D_Drmmr stated?
    When you try to learn something new in C++, it's best to start with a small example to get familiar with the topic before using those techniques in an existing program. Just write a simple program that writes an int, a double and a string to a file and reads it back.
    Regards,

    Paul McKenzie

  2. #17
    Join Date
    Oct 2013
    Location
    Maysville, KY
    Posts
    18

    Re: Save/load functions not working

    Code:
    #include <iostream>
    
    using namespace std;
    
    class FileIO
    {
    public:
        int numInt;
        double numDouble;
        string name;
    };
    
    int main()
    {
        FileIO file;
    
        file.numInt = 1;
        file.numDouble = 1.5;
        file.name = "Bob";
    
        ofstream saveFile("file.bin", ios::binary);
        saveFile.write((char *)&file, sizeof(file));
        saveFile.close();
    
        FileIO file2;
        ifstream loadFile("file.bin", ios::binary);
        loadFile.read((char *)&file2, sizeof(file2));
        cout << file2.numInt << endl << file2.numDouble << endl << file2.name << endl;
        loadFile.close();
    
    
    
    
    }
    Here's the example I made. It works fine. I just don't understand why it doesn't work in my actual program, I believe I did everything the same. As far as I know. It might just be some newbie mistake, but I'm not so sure.

  3. #18
    Join Date
    Apr 1999
    Posts
    27,449

    Re: Save/load functions not working

    Quote Originally Posted by KruSuPhy View Post
    Here's the example I made. It works fine.
    It doesn't work fine.
    Code:
    #include <iostream>
    
    using namespace std;
    
    class FileIO
    {
    public:
        int numInt;
        double numDouble;
       string name;
    };
    
    int main()
    {
        FileIO file;
    
        file.numInt = 1;
        file.numDouble = 1.5;
        file.name = "Bob";
    
        ofstream saveFile("file.bin", ios::binary);
        saveFile.write((char *)&file, sizeof(file));
        saveFile.close();
    
        FileIO file2;
        ifstream loadFile("file.bin", ios::binary);
        loadFile.read((char *)&file2, sizeof(file2));
        cout << file2.numInt << endl << file2.numDouble << endl << file2.name << endl;
        loadFile.close();
    }
    You see what's in red? You cannot save or read from the file like this. I already mentioned this to you.

    Your class has a std::string type, and that cannot be saved to a file or read from a file using this technique. That technique only works for POD types. It doesn't matter if it seems to work, it is wrong.

    I wish C++ centric websites quit posting this as an example of saving a file. Too many new programmers use it as a template in saving files "in binary", and wind up in the same mess you're in now.

    Again, write each item out to the file one item at a time.

    Regards,

    Paul McKenzie
    Last edited by Paul McKenzie; October 21st, 2013 at 08:20 AM. Reason: Changed non-POD to POD

  4. #19
    Join Date
    Apr 1999
    Posts
    27,449

    Re: Save/load functions not working

    To prove my point, try this program:
    Code:
    #include <iostream>
    #include <string>
    #include <fstream>
    
    class FileIO
    {
        public:
            int numInt;
            double numDouble;
            std::string name;
    };
    
    using namespace std;
    
    int main()
    {
        FileIO file;
    
        file.numInt = 1;
        file.numDouble = 1.5;
        for (int i = 0; i < 1000; ++i )
            file.name += "Bob";   // create a very long name by concatenating Bob onto itself
    
        ofstream saveFile("file.bin", ios::binary);
        saveFile.write((char *)&file, sizeof(file));
        saveFile.close();
    
        FileIO file2;
        ifstream loadFile("file.bin", ios::binary);
        loadFile.read((char *)&file2, sizeof(file2));
        cout << file2.numInt << endl << file2.numDouble << endl << file2.name << endl;
        loadFile.close();
    }
    The code has made corrections to your previous posts (it was missing necessary #include files). But look what I have done -- I created a very long name just to show you this technique doesn't work.

    What do you see now when you save and read the name back? I doubt you will see "Bob" repeated 1000 times.

    I know you won't see the name, since sizeof(file) is the number of bytes that the class consists of, and you're using sizeof(file) to determine the number of bytes to read and write. The sizeof(file) will always be the same (probably less than 100), regardless of how many characters the std::string holds. So right there, there is no way for that code to work.

    Regards,

    Paul McKenzie

  5. #20
    Join Date
    Oct 2013
    Location
    Maysville, KY
    Posts
    18

    Re: Save/load functions not working

    Okay, I apologize, and I'm not doubting what you're saying at all. However, could you explain how my example is wrong? I tested it and it worked well enough. I'm not sure if I understand what's wrong with it other than the really long name part. If that's it, couldn't it be fixed with a character limit? However, I will write each item one at a time, but couldn't that run into the same problem, or does writing them separately eliminate that problem?

  6. #21
    Join Date
    Jul 2005
    Location
    Netherlands
    Posts
    2,042

    Re: Save/load functions not working

    Quote Originally Posted by KruSuPhy View Post
    Okay, I apologize, and I'm not doubting what you're saying at all. However, could you explain how my example is wrong? I tested it and it worked well enough. I'm not sure if I understand what's wrong with it other than the really long name part. If that's it, couldn't it be fixed with a character limit? However, I will write each item one at a time, but couldn't that run into the same problem, or does writing them separately eliminate that problem?
    Your code didn't work, it just seemed like it did. The reason for that is that the implementation of std::string can use what is known as a small string optimization. This means that small strings are stored in a fixed size buffer that is a member of std::string. When this happens and you store and load the bytes of the std::string instance to a file, it may happen to do what you wished. However, when you use a longer string (such that the small string optimization is not in effect, as Paul showed) or when you run your code on a different compiler, all of a sudden your program can crash.

    That's the hard part of programming in C++. When you make a mistake and your program is broken, you don't know what will happen. It may crash, or it may appear to work fine. It may work on your machine, but not on another machine. So either you must learn to write C++ programs in a way that you can guarantee the code will always work (compiled with any C++ compiler, running on any PC), or you will end up with broken programs that mysteriously stop working at the worst possible time. That's why you cannot learn C++ by trial-and-error. You need to follow a descend method (i.e. book) that teaches you how to write correct C++ code.
    Cheers, D Drmmr

    Please put [code][/code] tags around your code to preserve indentation and make it more readable.

    As long as man ascribes to himself what is merely a posibility, he will not work for the attainment of it. - P. D. Ouspensky

  7. #22
    Join Date
    Apr 1999
    Posts
    27,449

    Re: Save/load functions not working

    Quote Originally Posted by KruSuPhy View Post
    Okay, I apologize, and I'm not doubting what you're saying at all. However, could you explain how my example is wrong?
    Unlike other computer languages, when you make a mistake in C++, you are not guaranteed anything will work correctly, as D_Drmmr stated.
    I tested it and it worked well enough.
    C++ doesn't work that way. That code could run on 1,000 machines, but fail on machine 1,001. It could be ok today, but as soon as you change compiler, compiler options, etc. the code no longer works.

    As pointed out, the std::string class for your compiler more than likely uses a buffer for small strings, but that is an implementation detail. Nothing stops a compiler from implementing std::string to not using short string buffers. For example, earlier versions of Visual C++ do not use such a buffer, therefore your code would have failed even for short strings.
    I'm not sure if I understand what's wrong with it other than the really long name part.
    It is fundamentally wrong. Again, your class is a non-POD type due to it containing a std::string, and once it is of that type, you cannot use constructs such as your read and write code on such a type.
    If that's it, couldn't it be fixed with a character limit?
    No.
    However, I will write each item one at a time, but couldn't that run into the same problem, or does writing them separately eliminate that problem?
    Code:
    class FileIO
    {
        public:
            int numInt;
            double numDouble;
            std::string name;
    };
    //...
    FileIO file;
    //...
    saveFile << file.name;
    Do you understand the difference in doing this? The operator << is the "stream out" operator. It is overloaded to understand what a std::string is, and will extract the characters from the std::string and output those characters to a file. Your code doesn't do any of that -- it blindly gives write() a pointer and says "starting at this address, write sizeof(file) bytes". That doesn't tell write() anything about that special std::string type and how to get the data from this type.

    That's why I mentioned in my previous post about that example showing writing binary to a file, and how I wished websites (and even books) quit showing that example, or at the very least, warn the new programmers when it cannot be used. Too many new programmers stumble across this "binary saving/reading" code, and think it's sound and can be used universally. Nothing can be further from the truth.

    Regards,

    Paul McKenzie

  8. #23
    GCDEF is offline Elite Member Power Poster
    Join Date
    Nov 2003
    Location
    Florida
    Posts
    12,635

    Re: Save/load functions not working

    The problem is sizeof isn't always going to give you what you think it is. If your class contains a pointer for example, sizeof will tell you that pointer is 4 bytes long, without regard at all to the size of what it's pointing to. So when you go to save, your code won't save the correct amount of data, not will it follow to the pointer to save whatever that pointer's pointing to. You'll end up saving a number that means nothing when you read it back in, and not saving the data you were trying to save.

  9. #24
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,822

    Re: Save/load functions not working

    Quote Originally Posted by Paul McKenzie View Post
    Your class has a std::string type, and that cannot be saved to a file or read from a file using this technique. That technique only works for non-POD types. It doesn't matter if it seems to work, it is wrong.
    Only works for non-POD types??????
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  10. #25
    Join Date
    Apr 1999
    Posts
    27,449

    Re: Save/load functions not working

    Quote Originally Posted by 2kaud View Post
    Only works for non-POD types??????
    I corrected the post to state POD types.

    Regards,

    Paul McKenzie

  11. #26
    Join Date
    Oct 2013
    Location
    Maysville, KY
    Posts
    18

    Re: Save/load functions not working

    Okay, well, I finally understood what you all were telling me and went ahead and fixed it. It works/'seems' to work, so here's my code.
    Code:
    void Game::saveGame(Character player)
    {
        std::ofstream saveFile("savegame.bin", std::ios::binary);
        saveFile << player.name() << "\n";
        saveFile << player.hitPoints() << "\n";
        saveFile << player.strength() << "\n";
        saveFile << player.defense() << "\n";
        saveFile << player.speed() << "\n";
        saveFile << player.level() << "\n";
        saveFile << player.gold() << "\n";
        saveFile.close();
        std::cout << "Game Saved!" << std::endl;
    }
    
    void Game::loadGame()
    {
        std::ifstream loadFile("savegame.bin", std::ios::binary);
        Character player;
        loadFile >> player.m_name;
        loadFile >> player.m_hitPoints;
        loadFile >> player.m_strength;
        loadFile >> player.m_defense;
        loadFile >> player.m_speed;
        loadFile >> player.m_level;
        loadFile >> player.m_gold;
        startGame(player);
        loadFile.close();
    }
    Is there any way I could improve this code, or is it as it should be?

  12. #27
    Join Date
    Jan 2006
    Location
    Singapore
    Posts
    6,765

    Re: Save/load functions not working

    What happens if the player name contains a space, or do your disallow such names?

    For further exploration, you might want to consider if it makes sense to use purpose-built database to store the data persistently instead of coming up with a home brewed file format. It doesn't have to be a full blown external database as a database engine embedded into your program like SQLite could do well enough.
    C + C++ Compiler: MinGW port of GCC
    Build + Version Control System: SCons + Bazaar

    Look up a C/C++ Reference and learn How To Ask Questions The Smart Way
    Kindly rate my posts if you found them useful

  13. #28
    Join Date
    Oct 2013
    Location
    Maysville, KY
    Posts
    18

    Re: Save/load functions not working

    Well, I ran into that problem earlier. If the name contains a space, it only counts everything before the space. Which I assume you already knew. However, I'm not quite sure how to fix that. I'm sure it's probably something simple I just don't know how to do yet, and I'll look it up tomorrow night when I get home.
    And thanks for the link to SQLite, I'll check it out tomorrow as well!

  14. #29
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,822

    Re: Save/load functions not working

    Another possible way of storing the data would be as XML format. There are several free c++ XML libraries available.
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  15. #30
    Join Date
    Oct 2013
    Location
    Maysville, KY
    Posts
    18

    Re: Save/load functions not working

    I'm not quite sure how to implement the SQLite into my program, but i'm going to look it up and try.
    Also, as for the name with spaces problem I'm having, I attempted to use getline() for the input, but it didn't work. It would just go crazy and send into an infinite loop for some reason..
    Last edited by KruSuPhy; October 22nd, 2013 at 10:03 PM.

Page 2 of 3 FirstFirst 123 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured