本文首发于个人博客https://kezunlin.me/post/6887a6ee/,欢迎阅读!

serialize and deserialize a class in cpp

Guide

how to serialize string

size + data

with ostream/istream

native way with ostream/istream for example class MyClass with height,width,name fields.

class MyClass {
public:
    int height;
   int width;
   std::string name;
}

std::ostream& MyClass::serialize(std::ostream &out) const {
    out << height;
    out << ',' //number seperator
    out << width;
    out << ',' //number seperator
    out << name.size(); //serialize size of string
    out << ',' //number seperator
    out << name; //serialize characters of string
    return out;
}
std::istream& MyClass::deserialize(std::istream &in) {
    if (in) {
        int len=0;
        char comma;
        in >> height;
        in >> comma; //read in the seperator
        in >> width;
        in >> comma; //read in the seperator
        in >> len;  //deserialize size of string
        in >> comma; //read in the seperator
        if (in && len) {
            std::vector<char> tmp(len);
            in.read(tmp.data() , len); //deserialize characters of string
            name.assign(tmp.data(), len);
        }
    }
    return in;
}

overload for operator<< and operator>>

std::ostream& operator<<(std::ostream& out, const MyClass &obj)
{
    obj.serialize(out);
    return out;
}

std::istream& operator>>(std::istream& in, MyClass &obj)
{
    obj.deserialize(in);
    return in;
}

with boost serialization

archive file format

  • text: text_iarchive,text_oarchive field
  • xml: xml_iarchive,xml_oarchive, with BOOST_SERIALIZATION_NVP(field)
  • binary: binary_iarchive,binary_oarchive with stringstream or fstream.

text archive

change BOOST_SERIALIZATION_NVP(field) to field

xml archive

#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <iostream>
#include <fstream>
#include <sstream>

class Camera {

public:
    int id;
    std::string name;
    double pos;
};

namespace boost {
    namespace serialization {

        template<class Archive>
        void serialize(Archive& archive, Camera& cam, const unsigned int version)
        {
            archive & BOOST_SERIALIZATION_NVP(cam.id);
            archive & BOOST_SERIALIZATION_NVP(cam.name);
            archive & BOOST_SERIALIZATION_NVP(cam.pos);
        }

    } // namespace serialization
} // namespace boost

std::ostream& operator<<(std::ostream& cout, const Camera& cam)
{
    cout << cam.id << std::endl
        << cam.name << std::endl
        << cam.pos << std::endl;
    return cout;
}

void save()
{
    std::ofstream file("archive.xml");
    boost::archive::xml_oarchive oa(file);

    Camera cam;
    cam.id = 100;
    cam.name = "new camera";
    cam.pos = 99.88;

    oa & BOOST_SERIALIZATION_NVP(cam);
}

void load()
{
    std::ifstream file("archive.xml");
    boost::archive::xml_iarchive ia(file);
    Camera cam;
    ia & BOOST_SERIALIZATION_NVP(cam);
    std::cout << cam << std::endl;
}

void test_camera()
{
    save();
    load();
}

int main(int argc, char** argv)
{
    test_camera();
}

binary archive

void save_load_with_binary_archive()
{
    // binary archive with stringstream
    std::ostringstream oss;
    boost::archive::binary_oarchive oa(oss);

    Camera cam;
    cam.id = 100;
    cam.name = "new camera";
    cam.pos = 99.88;

    oa & (cam);

   # get binary content
    std::string str_data = oss.str();
    std::cout << str_data << std::endl;

    std::istringstream iss(str_data);
    boost::archive::binary_iarchive ia(iss);
    Camera new_cam;
    ia & (new_cam);
    std::cout << new_cam << std::endl;
}

binary archive with poco SocketStream

client.cpp

void test_client()
{
    SocketAddress address("127.0.0.1", 9911);
    StreamSocket socket(address);
    SocketStream stream(socket);
    //Poco::StreamCopier::copyStream(stream, std::cout);

    boost::archive::binary_oarchive oa(stream);
    Camera cam;
    cam.id = 100;
    cam.name = "new camera";
    cam.pos = 99.88;

    oa & (cam);
}

server.cpp

void run()
    {
        Application& app = Application::instance();
        app.logger().information("Request from " + this->socket().peerAddress().toString());
        try
        {
            SocketStream stream(this->socket());
            //Poco::StreamCopier::copyStream(stream, std::cout);

            boost::archive::binary_iarchive ia(stream);
            Camera new_cam;
            ia & (new_cam);
            std::cout << new_cam << std::endl;
        }
        catch (Poco::Exception& exc)
        {
            app.logger().log(exc);
        }
    }

notes on std::string

Even know you have seen that they do the same, or that .data() calls .c_str(), it is not correct to assume that this will be the case for other compilers. It is also possible that your compiler will change with a future release.

2 reasons to use std::string:

std::string can be used for both text and arbitrary binary data.

//Example 1
//Plain text:
std::string s1;
s1 = "abc";
s1.c_str();

//Example 2
//Arbitrary binary data:
std::string s2;
s2.append("a\0b\0b\0", 6);
s2.data();

boost archive style

intrusive

  • private template<class Archive> void serialize(Archive& archive, const unsigned int version)
  • friend class boost::serialization::access;
class Camera {

public:
    int id;
    std::string name;
    double pos;

private:
    friend class boost::serialization::access;
    template<class Archive>
    void serialize(Archive& archive, const unsigned int version)
    {
        archive & BOOST_SERIALIZATION_NVP(id);
        archive & BOOST_SERIALIZATION_NVP(name);
        archive & BOOST_SERIALIZATION_NVP(pos);
    }
};

non-intrusive

class Camera {

public:
    int id;
    std::string name;
    double pos;
};


namespace boost {
    namespace serialization {

        template<class Archive>
        void serialize(Archive& archive, Camera& cam, const unsigned int version)
        {
            archive & BOOST_SERIALIZATION_NVP(cam.id);
            archive & BOOST_SERIALIZATION_NVP(cam.name);
            archive & BOOST_SERIALIZATION_NVP(cam.pos);
        }

    } // namespace serialization
} // namespace boost

boost archive type

shared_ptr

boost::shared_ptr<T> instead of std::shared_prt<T>
and

#include <boost/serialization/shared_ptr.hpp>

Reference

History

  • 20180128: created.
  • 20180129: add intrusive,non-intrusive part.

Copyright

01-07 10:29