Boost serialization polymorphic register(export) n

2020-05-24 21:16发布

问题:

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.

回答1:

Before calling BOOST_CLASS_EXPORT_* you should include the archives which you want to use. The makro 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 Serializsation Documentation

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