[SOLVED]streaming object to file (C++)

Started by
13 comments, last by experiment 16 years ago
Internet searches say that I should do it like this:
void jSaveObj2D(jObject2D Obj2D, char *fileName)
{
	std::ofstream file(fileName, std::ios::binary);
	file.write((char *)(&Obj2D), sizeof(jObject2D));
	file.close();
}

void jLoadObj2D(jObject2D Obj2D, char *fileName)
{
	std::ifstream file(fileName, std::ios::binary);
	if(!file)
	{
		std::cout << "\nfile not found..";
	}
	else
	{
		file.read((char *)(&Obj2D), sizeof(jObject2D));
	}
	file.close();
}



but it doesn't seem to work.. I'm not sure why.. Does it matter if that structure contains other structures..? Example:

struct jVector2D {
    float x, y;
};

class jObject2D {
public:
    std::vector<jVector2D> Vertices;
    translate(float x, float y);
private:
    jVector2D position;
};



How can I stream I/O jObject2D to/from file..? [Edited by - experiment on March 27, 2008 1:26:37 PM]
Advertisement
A naive bitwise approach like that isn't going to work except in the simplest of cases, and it's not guaranteed to work even then. It's simply bad code. Real-world serialization is a nontrivial problem with no simple solutions in the general case. A couple links you should definitely familiarize yourself with:

C++ FAQ Lite: Serialization

Boost Serialization library
I don't want to familiarize myself with serialization. I just want to know how to store a -jObject2D- into binary (from the example i gave before)..

PS: That explanation link didn't help me..
Quote:I just want to know how to store a -jObject2D- into binary (from the example i gave before).

You can't just dump out/slurp up a non-trivial structure in the manner you are attempting. You will have to serialize your structure properly. All this means is you will have to do some additional work (beyond just file.write(struct) ). The simplest solution is to write out your structure member by member, and then read it back in the same manner. When it comes to arrays/vectors/lists, you may also need to store additional meta information such as the length of the array, so that you can pre-allocate space before reading the data back in, and so that you will know how much of the following data in the file belongs to that array. For your case, you could store the length of the Vertices vector, then each jVector2D in the vector as a float float pair. Then store position as a float float pair. Then when you read it back in, you know that the first value is the number of pairs of floats to read to populate your Vertices array, and then the final float pair is assigned to "position".

Quote:I don't want to familiarize myself with serialization.

Oh, sorry then. Unfortunately, there is no general solution for what you are trying to do. The problem is solved using serialization. I was under the impression that you wanted a solution to your problem. If that is not the case, why did you even post your question?

[Edited by - CodeMunkie on March 25, 2008 11:32:27 AM]
"When you die, if you get a choice between going to regular heaven or pie heaven, choose pie heaven. It might be a trick, but if it's not, mmmmmmm, boy."
How to Ask Questions the Smart Way.
Quote:Original post by experiment
I don't want to familiarize myself with serialization. I just want to know how to store a -jObject2D- into binary (from the example i gave before)..


Unlike most other languages, C++ provides no serialization system for its objects. As such, you are faced with three alternatives:

  1. Find a third party serialization system, learn how to use it, and apply it to your specific problem. Boost.Serialization is an example of such a system.
  2. Learn how to serialize objects without third party libraries, and do it yourself. This might be shorter on simple cases, but will be longer and more error-prone if you have to work with many different object types.
  3. Use a different language. For instance, Java, Objective Caml and all .NET languages (C#, VB.NET) provide automatic serialization through a single function call


The solution you provided involves doing (char *)(&Obj2D). This examines the bytes that are present at the memory location of your object, which:
  • Is only a small part of the object data, since the object may be spread over several locations through use of pointers.
  • Depends on the current memory layout of the program. That is, the same bytes used in another executable (or in another run of the same executable, or even the same run of the same executable a few seconds later) will represent a different object, which will most of the time be invalid.


The only situation where the memory layout of an object is a correct and serializable representation of that object, is when the object is of a POD type: either a basic non-pointer type (integers or floating-point numbers, mostly) or a structure type which contains no constructors, no destructors, no base classes, and no non-POD members. As soon as you include a non-POD member (such as std::vector) the memory layout of your object ceases to be a complete and persistent representation of its state, and thus cannot be used to save the object to a file reliably.
Quote:Original post by ToohrVyk
The only situation where the memory layout of an object is a correct and serializable representation of that object, is when the object is of a POD type: either a basic non-pointer type (integers or floating-point numbers, mostly) or a structure type which contains no constructors, no destructors, no base classes, and no non-POD members. As soon as you include a non-POD member (such as std::vector) the memory layout of your object ceases to be a complete and persistent representation of its state, and thus cannot be used to save the object to a file reliably.


It's even worse than that, of course. If a compound POD type contains a pointer member, it's probably not correct to write out objects of that type byte-for-byte.

You also have padding issues to overcome. So you really do need to look in to serialization solutions, whether you want to or not. C++ just doesn't have enough introspection support to do this for you.
Quote:Original post by experiment
I don't want to familiarize myself with serialization. I just want to know how to store a -jObject2D- into binary (from the example i gave before)..


"I don't want to familiarize myself with driving. I just want to know how to get my car from point A to point B."
The analogy with driving was funny, although it'd be more like:
"I don't want to familiarize myself with driving. I just want someone to get my car from point A to point B for me."
Which means: I was just hoping someone would easily write a serialization example code (based on example I gave). But I guess serialization in C++ isn't so straightforward as I thought.. I knew there'd be crap with std::vector..

But thanks everyone for taking your time to explain this. I'll try the Boost serialization library..
Quote:Original post by experiment
The analogy with driving was funny, although it'd be more like:
"I don't want to familiarize myself with driving. I just want someone to get my car from point A to point B for me."
Which means: I was just hoping someone would easily write a serialization example code (based on example I gave). But I guess serialization in C++ isn't so straightforward as I thought.. I knew there'd be crap with std::vector..


This statement has somewhat more far reaching implications than you'd imagine.

You're claiming you do not want to know anything at all about C++ memory layout and management, which means you'll be unable to develop anything non-trivial in C++.

When people say that C++ is difficult, complex and error prone, they do so for a reason.

Unless you clear these terms for yourself, you'll be running into many problems as soon as you start using pointers and references, and basic topics like shallow vs. deep copy, assignment operator, and other basic memory management.

Also: "file.close();" in the original example is not needed. It's quite important to understand why that is so.
Quote:Original post by experiment
The analogy with driving was funny, although it'd be more like:
"I don't want to familiarize myself with driving. I just want someone to get my car from point A to point B for me."
Which means: I was just hoping someone would easily write a serialization example code (based on example I gave). But I guess serialization in C++ isn't so straightforward as I thought.. I knew there'd be crap with std::vector..

But thanks everyone for taking your time to explain this. I'll try the Boost serialization library..


I outlined exactly what you need to do in my previous post.
"When you die, if you get a choice between going to regular heaven or pie heaven, choose pie heaven. It might be a trick, but if it's not, mmmmmmm, boy."
How to Ask Questions the Smart Way.

This topic is closed to new replies.

Advertisement