How to Implement Serialization in C++

C - serialization techniques

For each data structure, have a serialize_X function (where X is the struct name) which takes a pointer to an X and a pointer to an opaque buffer structure and calls the appropriate serializing functions. You should supply some primitives such as serialize_int which write to the buffer and update the output index.
The primitives will have to call something like reserve_space(N) where N is the number of bytes that are required before writing any data. reserve_space() will realloc the void* buffer to make it at least as big as it's current size plus N bytes.
To make this possible, the buffer structure will need to contain a pointer to the actual data, the index to write the next byte to (output index) and the size that is allocated for the data.
With this system, all of your serialize_X functions should be pretty straightforward, for example:

struct X {
int n, m;
char *string;
}

void serialize_X(struct X *x, struct Buffer *output) {
serialize_int(x->n, output);
serialize_int(x->m, output);
serialize_string(x->string, output);
}

And the framework code will be something like:

#define INITIAL_SIZE 32

struct Buffer {
void *data;
size_t next;
size_t size;
}

struct Buffer *new_buffer() {
struct Buffer *b = malloc(sizeof(Buffer));

b->data = malloc(INITIAL_SIZE);
b->size = INITIAL_SIZE;
b->next = 0;

return b;
}

void reserve_space(Buffer *b, size_t bytes) {
if((b->next + bytes) > b->size) {
/* double size to enforce O(lg N) reallocs */
b->data = realloc(b->data, b->size * 2);
b->size *= 2;
}
}

From this, it should be pretty simple to implement all of the serialize_() functions you need.

EDIT:
For example:

void serialize_int(int x, Buffer *b) {
/* assume int == long; how can this be done better? */
x = htonl(x);

reserve_space(b, sizeof(int));

memcpy(((char *)b->data) + b->next, &x, sizeof(int));
b->next += sizeof(int);
}

EDIT:
Also note that my code has some potential bugs. There is no provision for error handling and no function to free the Buffer after you're done so you'll have to do this yourself. I was just giving a demonstration of the basic architecture that I would use.

C# force subclass to implement Serializable

The short answer is No you can't enforce an Attribute through an interface.
In principle, interfaces are about contracts (behaviour) while serialisation is about state which is not normally reflected in interfaces.

The options you have are:

  • Instead of using an interface for "storable" objects use an abstract class (like StorableBase) that consumer code should inherit from. Main drawback of this is that it restricts the types of classes the consumer code can use with your library. Also note that not all serialization libraries check all the class hierarchy when looking for Serializable attribute and some might check only the concrete class. You can on top of that implement the ISerializable interface on that abstract class to have more control over the serialisation process. See here for details.

  • Roslyn introduced the concept of Code Analyzers. You can create a custom code analyzer that checks at compile time for your rule. See here for more details and an example.

how to serialize a struct in c?

This answer is besides the problems with your malloc.

Unfortunately, you cannot find a nice trick that would still be compatible with the standard. The only way of properly serializing a structure is to separately dissect each element into bytes, write them to an unsigned char array, send them over the network and put the pieces back together on the other end. In short, you would need a lot of shifting and bitwise operations.

In certain cases you would need to define a kind of protocol. In your case for example, you need to be sure you always put the object p is pointing to right after struct A, so once recovered, you can set the pointer properly. Did everyone say enough already that you can't send pointers through network?

Another protocolish thing you may want to do is to write the size allocated for the flexible array member s in struct B. Whatever layout for your serialized data you choose, obviously both sides should respect.

It is important to note that you cannot rely on anything machine specific such as order of bytes, structure paddings or size of basic types. This means that you should serialize each field of the element separately and assign them fixed number of bytes.

C++: how to serialize/deserialize objects without the use of libraries?

One pattern is to implement an abstract class the defines functions for serialization and the class defines what goes into the serializer and what comes out. An example would be:

class Serializable
{
public:
Serializable(){}
virtual ~Serializable(){}

virtual void serialize(std::ostream& stream) = 0;
virtual void deserialize(std::istream& stream) = 0;
};

You then implement Serializable interface for the class/struct that you want to serialize:

struct PersonInfo : public Serializable // Yes! It's possible
{
unsigned int age_;
string name_;
enum { undef, man, woman } sex_;

virtual void serialize(std::ostream& stream)
{
// Serialization code
stream << age_ << name_ << sex_;
}

virtual void deserialize(std::istream& stream)
{
// Deserialization code
stream >> age_ >> name_ >> sex_;
}
};

Rest I believe you know. Here's a few hurdles to pass though and can be done in your leisure:

  1. When you write a string to the stream with spaces in it and try to read it back, you will get only one portion of it and rest of the string 'corrupts' the values read after that.
  2. How can you program it such that it's cross-platform (little-endian vs big-endian)
  3. How can your program automatically detect, which class to create when deserializing.

Clues:

  1. Use custom serializer that has functions to write bool, int, float, strings, etc.
  2. Use a string to represent the object type being serialized and use factory to create an instance of that object when deserializing.
  3. Use predefined macros to determine which platform your code is being compiled.
  4. Always write files in a fixed endian and make the platforms that use the other endianess adjust to that.


Related Topics



Leave a reply



Submit