1

I'm attempting to implement a Save/Load feature into my small game. To accomplish this I have a central class that stores all the important variables of the game such as position, etc. I then save this class as binary data to a file. Then simply load it back for the loading function. This seems to work MOST of the time, but if I change certain things then try to do a save/load the program will crash with memory access violations. So, are classes guaranteed to have the same structure in memory on every run of the program or can the data be arranged at random like a struct?

Response to Jesus - I mean the data inside the class, so that if I save the class to disk, when I load it back, will everything fit nicely back.

Save

fout.write((char*) &game,sizeof Game);

Load

fin.read((char*) &game, sizeof Game);
Stuart Golodetz
  • 20,238
  • 4
  • 51
  • 80
Grizz
  • 603
  • 2
  • 7
  • 11
  • Do you mean the data inside the class or the address of the pointer to the class? – Jesus Ramos Jan 28 '12 at 23:42
  • 3
    Related: http://stackoverflow.com/questions/234724/how-to-serialize-in-c – ta.speot.is Jan 28 '12 at 23:48
  • 1
    Please define what you mean by "change certain things". Do you mean recompile the code with changes? Change how you run the program? Using the same compiler (including version), on the same architecture, using the same optimization settings, on the same code, you should technically get the same structure within memory AFAIK. – Daniel Arndt Jan 28 '12 at 23:55
  • I mean change data values in the class. Not recompiling or anything. – Grizz Jan 28 '12 at 23:56

4 Answers4

4

Your approach is extremely fragile. With many restrictions, it can work. These restrictions are not worth subjecting your users (or yourself!) to in typical cases.

Some Restrictions:

  • Never refer to external memory (e.g. a pointer or reference)
  • Forbid ABI changes/differences. Common case: memory layout and natural alignment on 32 vs 64 will vary. The user will need a new 'game' for each ABI.
  • Not endian compatible.
  • Altering your type's layouts will break your game. Changing your compiler options can do this.
  • You're basically limited to POD data.
  • Use offsets instead of pointers to refer to internal data (This reference would be in contiguous memory).

Therefore, you can safely use this approach in extremely limited situations -- that typically applies only to components of a system, rather than the entire state of the game.

Since this is tagged C++, "boost - Serialization" would be a good starting point. It's well tested and abstracts many of the complexities for you.

justin
  • 104,054
  • 14
  • 179
  • 226
  • What is a sensible alternative? It seems that writing functions to manually save to disk would be tedious and require altering if the game version changes. – Grizz Jan 29 '12 at 00:06
  • @user1065671 If you don't like tediousness, C++ might not be the best choice, though I'm sure there are many serialization libraries that can help you with this. – Trillian Jan 29 '12 at 00:15
  • 1
    @user1065671: Tedious? Yes. But that's what you've got to do if you want to directly save and load objects in any way that is even *close* to consistent. [Boost's Serialization library](http://www.boost.org/doc/libs/1_48_0/libs/serialization/doc/index.html) makes it as painless as possible, but you'll still have to write functions to serialize each member. Boost.Serialization does have some nice features, like version support, as well as the ability to do it without being intrusive on the internals of the class. – Nicol Bolas Jan 29 '12 at 00:17
  • @user1065671 I've referred you to check out boost serialization in an edit to my answer. The topic/problem is complex for a number of reasons (some are outlined above). Robust support of serialization is not trivial, but a good serialization lib can abstract that. You really do not need to spend much time rewriting what you have already written when you change your game's model/version -- usually only after you have introduced changes (e.g. moved something to another class/component or altered a structure to have different member-wise logic). – justin Jan 29 '12 at 00:22
  • @Trillian The C++ Middleware Writer reduces the amount of boiler plate code you have to write by creating/updating the marshalling functions for you. –  Jan 30 '12 at 07:22
2

Even if this would work, just don't do it. Define a file format at the byte-level and write sensible 'convert to file format' and 'convert from file format' functions. You'll actually know the format of the file. You'll be able to extend it. Newer versions of the program will be able to read files from older versions. And you'll be able to update your platform, build tools, and classes without fear of causing your program to crash.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
1

Yes, classes and structures will have the same layout in memory every time your program runs., although I can't say if the standard enforces this. The machine code generated by C++ compilers use "hard-coded" offsets to access type fields, so they are fixed. Realistically, the layout will only change if you modify the C++ class definition (field sizes, order, virtual methods, etc.), compile with a different compiler or change compiler options.

As long as the type is POD and without pointer fields, it should be safe to simply dump it to a file and read it back with the exact same program. However, because of the above-mentionned concerns, this approach is quite inflexible with regard to versionning and interoperability.

[edit]

To respond to your own edit, do not do this with your "Game" object! It certainly has pointers to other objects, and those objects will not exist anymore in memory or will be elsewhere when you'll reload your file.

Trillian
  • 6,207
  • 1
  • 26
  • 36
0

You might want to take a look at this.

Classes are not guaranteed to have the same structure in memory as pointers can point to different locations in memory each time a class is created.

However, without posting code it is difficult to say with certainty where the problem is.

Community
  • 1
  • 1
ose
  • 4,065
  • 2
  • 24
  • 40
  • A pointer which points to a different location in memory should not change the _structure_ in which it is stored, only the value within this structure. How you save the pointed to structure is a different story. – Daniel Arndt Jan 28 '12 at 23:52