boostboost-serialization

Boost serialization polymorphic register(export) not working across files


I am using boost::serialization in my project. The project is large, and serializes my objects in several places. According to the documentation here, I should export my class with two separated step.

  1. BOOST_EXPORT_KEY() in .h file, witch contains the declaration.
  2. BOOST_EXPOET_IMPLEMENT() in .cpp file, witch contains the instantiation(definition) of the exporting.

hier.h the class hierarchy, there are 3 classes in the hierarchy.

/*
B <---+--- D1
      |
      +--- D2
*/

#include <boost/serialization/base_object.hpp>                                                                                                                                                                 

class B {                                                                                                                                                                                                      
public:                                                                                                                                                                                                        
    virtual ~B() {}                                                                                                                                                                                            
    template < typename Ar >                                                                                                                                                                                   
    void serialize(Ar& ar, const int) {                                                                                                                                                                        
    }                                                                                                                                                                                                          
} ;                                                                                                                                                                                                            

class D1 : public B {                                                                                                                                                                                          
public:                                                                                                                                                                                                        
    virtual ~D1() {}                                                                                                                                                                                           
    template < typename Ar > void serialize(Ar& ar, const int) {                                                                                                                                               
        boost::serialization::base_object<B>(*this);                                                                                                                                                           
    }                                                                                                                                                                                                          
} ;                                                                                                                                                                                                            

class D2 : public B {                                                                                                                                                                                          
public:                                                                                                                                                                                                        
    template < typename Ar > void serialize(Ar& ar, const int) {                                                                                                                                               
        boost::serialization::base_object<B>(*this);                                                                                                                                                           
    }                                                                                                                                                                                                          
    virtual ~D2() {}                                                                                                                                                                                           
} ;                                                                                                                                                                                                            

#include <boost/serialization/export.hpp>                                                                                                                                                                      

BOOST_CLASS_EXPORT_KEY(B);                                                                                                                                                                                     
BOOST_CLASS_EXPORT_KEY(D1);                                                                                                                                                                                    
BOOST_CLASS_EXPORT_KEY(D2);

And a hier.cpp contains the implementation:

#include <boost/serialization/export.hpp>
#include "hier.h"

BOOST_CLASS_EXPORT_IMPLEMENT(D1);
BOOST_CLASS_EXPORT_IMPLEMENT(D2);

And a main.cpp use the serialization:

#include <iostream>                                                                                                                                                                                            
#include <sstream>                                                                                                                                                                                             
#include <boost/archive/text_iarchive.hpp>                                                                                                                                                                     
#include <boost/archive/text_oarchive.hpp>                                                                                                                                                                     
#include <boost/serialization/export.hpp>                                                                                                                                                                      
#include "hier.h"                                                                                                                                                                                              

int main(int argc, char* argv[])                                                                                                                                                                               
{                                                                                                                                                                                                              
    B* d1 = new D1();                                                                                                                                                                                          
    B* d2 = new D2();                                                                                                                                                                                          
    std::ostringstream os;                                                                                                                                                                                     
    boost::archive::text_oarchive oa (os);                                                                                                                                                                     
    oa & d1 & d2;                                                                                                                                                                                              
}

It compiled without any problem, but run it will cause:

terminate called after throwing an instance of 'boost::archive::archive_exception'
  what():  unregistered class - derived class not registered or exported

Which means the derived class is not registered, means the registration in the hier.cpp is not working. But that is really strange, because:

  1. If I register implementation is both main.cpp and hier.cpp, it issue duplicated definition while linking. Means the registration in hier.cpp is OK and is exposed into the linkers visibility., otherwise there will be no duplicated definition error.

  2. If I register implementation only in main.cpp, it runs OK.

I am really confused in that situation. Any comment and suggestion is appreciated. Thanks in advance.


Solution

  • Before calling BOOST_CLASS_EXPORT_* you should include the archives which you want to use. The maсro then adds specific serialize-functions for the headers.

    This means you should change your code in hier.cpp to the following:

    #include <boost/serialization/export.hpp>
    #include <boost/archive/text_iarchive.hpp>
    #include <boost/archive/text_oarchive.hpp>
    #include "hier.h"
    
    BOOST_CLASS_EXPORT_IMPLEMENT(D1);
    BOOST_CLASS_EXPORT_IMPLEMENT(D2);
    

    The code in hier.h changes accordingly:

    #include <boost/serialization/export.hpp>
    #include <boost/archive/text_iarchive.hpp>
    #include <boost/archive/text_oarchive.hpp>
    
    BOOST_CLASS_EXPORT_KEY(B);
    BOOST_CLASS_EXPORT_KEY(D1);
    BOOST_CLASS_EXPORT_KEY(D2);
    

    Sources:
    Boost Serialization Documentation

    PS:
    I do not know if this is solving your problem, but I think it could be causing some trouble. I think it's worth a try.