How to Serialize and Deserialize a Class in C++

Is it possible to serialize and deserialize a class in C++?

The Boost::serialization library handles this rather elegantly. I've used it in several projects. There's an example program, showing how to use it, here.

The only native way to do it is to use streams. That's essentially all the Boost::serialization library does, it extends the stream method by setting up a framework to write objects to a text-like format and read them from the same format.

For built-in types, or your own types with operator<< and operator>> properly defined, that's fairly simple; see the C++ FAQ for more information.

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.

Is it possible to Serialize and Deserialize objects in C++?

Check this out:

http://www.functionx.com/cpp/articles/serialization.htm

or use

Boost:Serialization
http://www.boost.org/doc/libs/1_36_0/libs/serialization/doc/index.html

How to serialize / deserialize INTs in C++

First of all, there is a little "inconsistency": you're asking for binary serialization, in something that looks like a text file. I will assume you really want a binary output.

The only thing to take care about when serializing integers is the endianness of the machine (even though most of machines are little endian).

In C++17 or lower the easiest way is a runtime check like

inline bool littleEndian()
{
static const uint32_t test = 0x01020304;
return *((uint8_t *)&test) == 0x04;
}

C++20 introduces a compile-time check so you can rewrite the previous as

constexpr bool littleEndian()
{
return std::endian::native == std::endian::little;
}

At this point what you want, is writing in a standard way all integers.
Usually BigEndian is the standard.

template <typename T>
inline static T revert(T num)
{
T res;
for (std::size_t i = 0; i < sizeof(T); i++)
((uint8_t *)&res)[i] = ((uint8_t *)&num)[sizeof(T) - 1 - i];
return res;
}

at this point your serializer would be:

template <typename T>
void serialize(T TestVariable, std::string& FilePath)
{

static_assert(std::is_integral<T>::value); //check that T is of {char, int, ...} type
static_assert(!std::is_reference<T>::value); //check that T is not a reference

std::ofstream o(FilePath);
if (littleEndian())
TestVariable = revert(TestVariable);
o.write((char *)&TestVariable, sizeof(T));
}

and your deserializer would be

template <typename T>
void deserialize(T *TestVariable, std::string FilePath)
{
static_assert(std::is_integral<T>::value);
std::ifstream i(FilePath);
i.read((char *)TestVariable, sizeof(T));
if (littleEndian())
*TestVariable = revert(*TestVariable);
}

Notice: this code is just an example that works with your interface, you just have to include <iostream>, <fstream> and if you're using the c++20 version, include <bit>

How do you serialize an object in C++?

Talking about serialization, the boost serialization API comes to my mind. As for transmitting the serialized data over the net, I'd either use Berkeley sockets or the asio library.

If you want to serialize your objects to a byte array, you can use the boost serializer in the following way (taken from the tutorial site):

#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
class gps_position
{
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & degrees;
ar & minutes;
ar & seconds;
}
int degrees;
int minutes;
float seconds;

public:
gps_position(){};
gps_position(int d, int m, float s) :
degrees(d), minutes(m), seconds(s)
{}
};

Actual serialization is then pretty easy:

#include <fstream>
std::ofstream ofs("filename.dat", std::ios::binary);

// create class instance
const gps_position g(35, 59, 24.567f);

// save data to archive
{
boost::archive::binary_oarchive oa(ofs);
// write class instance to archive
oa << g;
// archive and stream closed when destructors are called
}

Deserialization works in an analogous manner.

There are also mechanisms which let you handle serialization of pointers (complex data structures like tress etc are no problem), derived classes and you can choose between binary and text serialization. Besides all STL containers are supported out of the box.



Related Topics



Leave a reply



Submit