Hi,

 

I’m trying to serialize a derived object with polymorphism into a file and deserialize to a base class pointer. This works when I use the register_type function but not the BOOST_CLASS_EXPORT_KEY() and BOOST_CLASS_IMPLEMENT() macros. I need to use the macros since I am using shared libraries. Here is a sample of code to demonstrate the problem. When run it gets a unregistered class exception. I’m using RHEL 7.4 with Boost 1.53.

 

cat testera.h

#ifndef testera_h

#define testera_h

 

#include <boost/serialization/serialization.hpp>

#include <boost/archive/polymorphic_oarchive.hpp>

#include <boost/archive/polymorphic_iarchive.hpp>

#include <boost/serialization/export.hpp>

#include <boost/serialization/string.hpp>

 

class A

{

private:

        friend class boost::serialization::access;

 

        template< class Arch >

        void

        serialize( Arch &ar, const unsigned int ver );

 

public:

        A();

 

        virtual ~A() {}

 

        void setStr( const std::string &s );

        std::string getStr();

 

protected:

        std::string myStr;

};

 

BOOST_CLASS_EXPORT_KEY(A)

 

#endif

 

boost_ptr> cat testera.C

#include "testera.h"

 

BOOST_CLASS_EXPORT_IMPLEMENT(A)

 

 

template

void

A::serialize<boost::archive::polymorphic_oarchive>( boost::archive::polymorphic_oarchive &ar, const unsigned int ver );

 

template

void

A::serialize<boost::archive::polymorphic_iarchive>( boost::archive::polymorphic_iarchive &ar, const unsigned int ver );

 

A::A() : myStr( "a" )

{

}

 

void

A::setStr( const std::string &s )

{

        myStr = s;

}

 

std::string

A::getStr()

{

        return myStr;

}

 

 

template<class Arch>

void

A::serialize( Arch &ar, const unsigned int ver )

{

        ar & myStr;

}

 

boost_ptr> cat testerb.h

#ifndef testerb_h

#define testerb_h

 

#include "testera.h"

 

class B : public A

{

private:

        friend class boost::serialization::access;

 

        template< class Arch >

        void

        serialize( Arch &ar, const unsigned int ver );

 

public:

        B();

 

        virtual ~B() {}

 

        void set( const int i );

        int get();

 

protected:

        int myI;

};

 

BOOST_CLASS_EXPORT_KEY(B)

#endif

 

boost_ptr> cat testerb.C

#include "testerb.h"

 

BOOST_CLASS_EXPORT_IMPLEMENT(B)

 

template

void

B::serialize<boost::archive::polymorphic_oarchive>( boost::archive::polymorphic_oarchive &ar, const unsigned int ver );

 

template

void

B::serialize<boost::archive::polymorphic_iarchive>( boost::archive::polymorphic_iarchive &ar, const unsigned int ver );

B::B(): myI( 1 )

{

        myStr = "b";

}

 

void

B::set( const int i )

{

        myI = i;

}

 

int

B::get()

{

        return myI;

}

 

template< class Arch >

void

B::serialize( Arch &ar, const unsigned int ver )

{

        // boost::serialization::void_cast_register< B, A >( static_cast< B *>( NULL ), static_cast< A * >( NULL ) );

        ar & boost::serialization::base_object<A>( *this );

 

        ar & myI;

}

 

 

int main( int argc, char *argv[] )

{

        int ret = 0;

        B obj;

        B obj2;

 

        obj.set( 2 );

 

        A *ptr = NULL;

        B *bptr = NULL;

        bptr = &obj;

        ptr = &obj;

 

        if( argc > 1 )

        {

                std::string fl = argv[ 1 ];

                {

                        std::ofstream ofl( fl.c_str() );

                        boost::archive::polymorphic_text_oarchive toar( ofl );

       

                        boost::archive::polymorphic_oarchive *oar = &toar;

                       

                        /*

                        oar->register_type(static_cast<A *>(NULL));

                        oar->register_type(static_cast<B *>(NULL));

                        */

                        try

                        {

                                *oar & obj;

                                // *oar & ptr;

                        }

                        catch( std::exception &e )

                        {

                                std::cerr << "Error: archive from B to file " << fl << " - " << e.what() << std::endl;

                                ret = 1;

                        }

                }

 

                if( ! ret )

                {

                        ptr = NULL;

                        bptr = NULL;

       

                        {

                                std::ifstream ifl( fl.c_str() );

                                boost::archive::polymorphic_text_iarchive tiar( ifl );

               

                                boost::archive::polymorphic_iarchive *iar = &tiar;

                                /*

                                iar->register_type(static_cast<A *>(NULL));

                                iar->register_type(static_cast<B *>(NULL));

                                */

                                try

                                {

                                        *iar & ptr;

                                        // *iar & bptr;

                                }

                                catch( std::exception &e )

                                {

                                        std::cerr << "Error: archive from file " << fl << " to B * - " << e.what() << std::endl;

                                        ret = 1;

                                }

                        }

       

 

                        if( ! ret )

                        {

                                // std::cout << bptr->get() << std::endl;

                                std::cout << static_cast<B*>( ptr )->get() << std::endl;

                        }

                }

        }     

        return ret;

}

 

testera and testerb are compiled into a shared library with this:

boost_ptr> cat Makefile_lib

CXXFLAGS = -c -ggdb3  -fPIC -funswitch-loops -fgcse-after-reload -std=c++11

LDFLAGS = -std=c++11 -lboost_serialization -lboost_thread -lboost_system -lboost_filesystem

 

OBJLOC = obj

 

OBJS = $(OBJLOC)/testera.o \

        $(OBJLOC)/testerb.o

 

LIBRARY_NAME = libtester.so

 

libs:$(LIBRARY_NAME)

 

$(LIBRARY_NAME): $(OBJS)

        ${CXX} -shared -o $@ $(OBJS)

 

$(OBJLOC)/%.o: ./%.C

        $(CXX) $(CXXFLAGS) ./$*.C -o $(OBJLOC)/$*.o

 

tester_mn is compiled into the executable with this:

boost_ptr> cat Makefile_mn

CXXFLAGS = -ggdb3  -funswitch-loops -fgcse-after-reload -std=c++11

LDFLAGS = -lboost_serialization -lboost_thread -lboost_system -lboost_filesystem -L. -ltester

 

 

tester_mn: tester_mn.o

        ${CXX} $(CXXFLAGS) $(LDFLAGS) tester_mn.C  -o $@

 

 

If I were to comment out the BOOST macros and uncomment the register_type() functions from tester_mn.C everything works. Is there a way to get the macros to work?

-- 

Ray Kosby

Software Engineer

Columbus Technologies and Services, Inc

www.columbususa.com

Office - (301) 286-5095, fax - (301) 286-7475

 

NASA Goddard Space Flight Center, MS 452.1

Bldg 13 Rm 141

8800 Greenbelt Rd

Greenbelt, MD 20771

USA