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