Boost logo

Boost Users :

Subject: [Boost-users] Serialization with BOOST _CLASS_EXPORT_KEY() is not the same as registert_type<>()
From: Kosby, Ray B. (GSFC-428.0)[COLUMBUS TECHNOLOGIES AND SERVICES INC] (ray.b.kosby_at_[hidden])
Date: 2018-09-25 14:30:34


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<http://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



Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net