Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to serialize object with shared_ptr member using boost

There are abstract I1 and derived C1.

There are abstract I2 and derived C2.

I1 have shared_ptr<I2>. How can I make them serializable using boost serializaton? I am attemtping do it, but my application get exception.

#include <sstream>
#include <boost/shared_ptr.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/shared_ptr.hpp>

struct I1
{
    I1() {}
    virtual ~I1() = 0 {}

    template<class Archive>
    void serialize(Archive &ar, const unsigned int version)
    {
    }
};

struct C1 : I1
{
    virtual ~C1() {}

    template<class Archive>
    void serialize(Archive &ar, const unsigned int version)
    {
        ar & boost::serialization::base_object<I1>(*this);
    }
};

struct I2
{
    virtual ~I2() = 0 {}

    template<class Archive>
    void serialize(Archive &ar, const unsigned int version)
    {
        ar & p;
    }

    boost::shared_ptr<I1> p;
};

struct C2 : I2
{
    C2() { p = boost::shared_ptr<I1>(new C1); }
    virtual ~C2() { }

    template<class Archive>
    void serialize(Archive &ar, const unsigned int version)
    {
        ar & boost::serialization::base_object<I2>(*this);
    }
};

int main()
{
    C2 c2;

    std::string s;
    std::stringstream ss(s);

    boost::archive::binary_oarchive oa(ss);
    oa.register_type<I1>();
    oa.register_type<C1>();
    oa.register_type<I2>();
    oa.register_type<C2>();

    oa << c2;

    boost::archive::binary_iarchive ia(ss);
    //ia.register_type<I1>(); // cannot instantiate abstract class
    ia.register_type<C1>();
    //ia.register_type<I2>(); // cannot instantiate abstract class
    ia.register_type<C2>();

    ia >> c2;
}
like image 964
Ufx Avatar asked Jul 30 '26 09:07

Ufx


1 Answers

The boost serialization documentation says here interesting things about BOOST_CLASS_EXPORT:

... BOOST_CLASS_EXPORT ...

Hence, the need for export is implied by the usage of a derived class that is manipulated via a pointer or reference to its base class.

Your p pointer does exactly that. Adding these macros to your code also gets rid of the ugly explicit register_type() calls from your main, which is also nice :)

So, this code seems to compile and work in VS2014:

#include <sstream>
#include <boost/shared_ptr.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/export.hpp>

struct I1
{
    I1() {}
    virtual ~I1() = 0 {}

    template<class Archive>
    void serialize(Archive &ar, const unsigned int version)
    {
    }
};

BOOST_CLASS_EXPORT(I1)

struct C1 : I1
{
    virtual ~C1() {}

    template<class Archive>
    void serialize(Archive &ar, const unsigned int version)
    {
        ar & boost::serialization::base_object<I1>(*this);
    }
};

BOOST_CLASS_EXPORT(C1)

struct I2
{
    virtual ~I2() = 0 {}

    template<class Archive>
    void serialize(Archive &ar, const unsigned int version)
    {
        ar & p;
    }

    boost::shared_ptr<I1> p;
};

BOOST_CLASS_EXPORT(I2)

struct C2 : I2
{
    C2() { p = boost::shared_ptr<I1>(new C1); }
    virtual ~C2() { }

    template<class Archive>
    void serialize(Archive &ar, const unsigned int version)
    {
        ar & boost::serialization::base_object<I2>(*this);
    }
};

BOOST_CLASS_EXPORT(C2)

int main()
{
    C2 c2;

    std::string s;
    std::stringstream ss(s);

    boost::archive::binary_oarchive oa(ss);
    oa << c2;

    boost::archive::binary_iarchive ia(ss);
    ia >> c2;
}

It is interesting, though, that the statement from Boost docs is obviously not true for all compilers, and lots of code examples on the internets just don't work in VS2014.

like image 59
Martin Prazak Avatar answered Aug 01 '26 21:08

Martin Prazak