简体   繁体   中英

boost serialization exception: unregistered class, serializing polymorphic base problem

i've been reading, cross-referencing, and ultimately not finding a coherent example and answer. what i'm trying to do is pretty simple, but i'm clearly missing something. in english, i've got a class structure with two abstract bases (pure BB derives from pure AA), which i manage as a:

std::vector<AA*>

i'd like to serialize another object containing this vector. everything except this vector serializes fine, but once it gets to the vector, it throws:

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

i've tried a few things, including explicitly registering the parent types prior to serialization, expressly declaring the base abstract classes as such with 'BOOST_SERIALIZATION_ASSUME_ABSTRACT', etc. however, i'm left with the exception at runtime.

i'd like to get this example (and solution) on the record so others can use this excellent, if a little opaque, library. once this example is square, i'll submit it to the boost serialization maintainers to include in either the FAQ or documentation as they see fit.

sample code to replicate the problem below:

/*
    g++ -Iinclude/ -Llib -lboost_serialization ~/Desktop/ser_ex.cpp -o stest
*/
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/serialization/vector.hpp>

#include <iostream>
#include <fstream>
#include <string>
#include <vector>

namespace bser = boost::serialization;
class AA
{
public:
    virtual void foo() = 0;
    std::string name;

    template<class Archive>
    void serialize(Archive & ar, unsigned int file_version)
    {
        ar & bser::make_nvp( "Name", name );
    }
};
BOOST_SERIALIZATION_ASSUME_ABSTRACT( AA );

class BB : public AA
{
public:
    virtual void foo() = 0;
    virtual void bar() = 0;
    int thing;

    template<class Archive>
    void serialize(Archive & ar, unsigned int file_version)
    {
        ar.template register_type< AA >();
        ar & bser::base_object< AA >( *this );
        ar & bser::make_nvp( "Thing", thing );
    }
};
BOOST_SERIALIZATION_ASSUME_ABSTRACT( BB );

class CC : public BB
{
public:
    virtual void foo() {}
    virtual void bar() {}
    int otherThing;

    template<class Archive>
    void serialize(Archive & ar, unsigned int file_version)
    {
        ar.template register_type< BB >();
        ar & bser::base_object< BB >( *this );
        ar & bser::make_nvp( "OtherThing", otherThing );
    }
};

int main (int argc, char const *argv[])
{
    const std::string filename( "my.serialized" );
    const std::string key( "AAVector" );

    std::vector< AA* > vv;
    vv.push_back( new CC );

    std::ofstream outfilestream( filename.c_str(), std::ios::binary );
    boost::archive::xml_oarchive out_archive( outfilestream );
    out_archive << boost::serialization::make_nvp( key.c_str(), vv );
    outfilestream.close();
}

I got this to work with minor modifications :

  • Replace ar & bser::base_object< AA >( *this ); in BB::serialize with :

     ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(AA); 
  • Replace ar & bser::base_object< BB >( *this ); in CC::serialize with :

     ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(BB); 
  • Add a BOOST_CLASS_EXPORT(CC) after CC definition. See this documentation section for an explanation.

It's also not the correct thing to do to register any abstract base. You'll run into problems with deserialization otherwise. You should be registering the derived classes in the derived, not the abstract base in the derived.

This seems to only matter for deserialization.

See deserialization from an abstract base fails for boost serialization

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM