0

I would like to serialize/deserialize some structured data in order to send it over the network via a char* buffer.

More precisely, suppose I have a message of type struct Message.

struct Message {
        Header header;
        Address address;
        size_t size; // size of data part
        char* data;
    } message 

In C, I would use something such as:

  size = sizeof(Header) + sizeof(Address) + sizeof(size_t) + message.size;
  memcpy(buffer, (char *) message, size);

to serialize, and

Message m = (Message) buffer;

to deserialize.

What would be the "right" way to do it in C++. Is it better to define a class rather than a struct. Should I overload some operators? are there alignment issues to consider?

EDIT: thanks for pointing the "char *" problem. The provided C version is incorrect. The data section pointed to by the data field should be copied separately.

5
  • 1
    And what's stopping you from doing the same in C++? Besides the fact that you don't seem to serialize the data field, and don't consider things like structure padding. Commented Mar 2, 2015 at 17:38
  • You wouldn't be sending that struct as-is over the network in C either. Try it and see if you don't get garbage or a segfault. (Without some special arrangement, the address stored in data has no meaning outside the process that created it.) Commented Mar 2, 2015 at 17:39
  • "In C, I would use something such as..." And you would be dead wrong. sizeof (struct Message) is readable, maintainable and correct. Your sum of three sizes is neither. Commented Mar 2, 2015 at 17:40
  • In C, you could do that if you had an unknown-sized array char data[]; rather than a pointer char * data;, as long as alignment and byte-ordering didn't bite you. But that's not quite supported in standard C++. Commented Mar 2, 2015 at 17:42
  • 1
    "Is it better to define a class rather than a struct." - they're exactly the same thing (apart from default access restrictions). Commented Mar 2, 2015 at 17:43

2 Answers 2

2

Actually there are many flavors:

You can boost let it do for you: http://www.boost.org/doc/libs/1_52_0/libs/serialization/doc/tutorial.html

Overloading the stream operators << for serialization and >> for deserialization works well with file and string streams

You could specify a constructor Message (const char*) for constructing from a char*.

I am a fan of static methods for deserialization like:

Message {
  ...
  static bool desirialize (Message& dest, char* source);
}

since you could catch errors directly when deserializing.

And the version you proposed is ok, when applying the modifications in the comments are respected.

Sign up to request clarification or add additional context in comments.

1 Comment

I would highly recommend the "let a serialization library do it for you" route unless you have a really good reason not to. There are just so many edge cases that you have to cover when you roll your own that the probability of errors is high.
0

Why not insert a virtual 'NetworkSerializable' Class into your inheritance tree? A 'void NetSend(fd socket)' method would send stuff, (without exposing any private data), and 'int(bufferClass buffer)' could return -1 if no complete, valid message was deserilalized, or, if a valid message has been assembled, the number of unused chars in 'buffer'.

That encapsulates all the assembly/disassembly protocol state vars and other gunge inside the class, where it belongs. It also allows message/s to be assembled from multiple stream input buffers.

I'm not a fan of static methods. Protocol state data associated with deserialization should be per-instance, (thread-safety).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.