How to serialize an object with shared_ptr using boost

There are abstract I1

and derivatives C1

.

There are abstract I2

and derivatives C2

.

I1

have shared_ptr<I2>

. How can I make them serializable using boost serializaton? I do this, but my application is getting an 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;
}

      

+3


source to share


3 answers


The batch serialization documentation says interesting things here about BOOST_CLASS_EXPORT

:

... BOOST_CLASS_EXPORT ...

Therefore, the need for an export is implied by the use of a derived class, which is controlled by a pointer or reference to its base class.

The pointer p

does exactly that. Adding these macros to your code also gets rid of the ugly explicit calls register_type()

from your main one, which is nice too :)



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;
}

      

Interestingly, however, the expression from the Boost docs is clearly wrong for all compilers, and a lot of code examples on the internet just don't work in VS2014.

+3


source


Add to

BOOST_SERIALIZATION_ASSUME_ABSTRACT(I1)
BOOST_SERIALIZATION_ASSUME_ABSTRACT(I2)

      

As per the documentation http://www.boost.org/doc/libs/1_39_0/libs/serialization/doc/traits.html#abstract

UPDATE

I just checked with VS2013RTM and Boost 1_55, this is JustWorks (TM), I

  • removed type registration for abstract bases (they can never be fully loaded from the archive)
  • added

    #pragma warning(disable: 4244)
    #include <boost/config/warning_disable.hpp>
    
          

    at the top of the file to disable known chat alerts



Compiled code and works without errors. For good style, you should probably

Here's the complete code I ended up with:

#pragma warning(disable: 4244)
#include <boost/config/warning_disable.hpp>
#include <sstream>
#include <boost/shared_ptr.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_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()
{
    boost::shared_ptr<I2> c2(new C2);

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

    boost::archive::text_oarchive oa(ss);
    oa.register_type<C1>();
    oa.register_type<C2>();

    oa << c2;
    std::cout << "Serialized form: '" << ss.str() << "'\n";

    boost::archive::text_iarchive ia(ss);
    ia.register_type<C1>();
    ia.register_type<C2>();

    ia >> c2;
}

      

And here's the output:

enter image description here

0


source


I think you should also not register your pure virtual classes in the output archive.

Alternatively, you can use export . After defining your classes, replace the rest of your code with the following:

#include <boost/serialization/export.hpp>
BOOST_CLASS_EXPORT(C1)
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;
}

      

I put the output archive in a separate block. I think it most likely works without it, but I want to make sure everything turns red (via out of scope).

0


source







All Articles