简体   繁体   中英

Boost serialization unregistered class errors

I cannot seem to get boost::serialization to work well. I have sprinkled the class .cpp files with BOOST_CLASS_EXPORT_GUID macros, after including the class and archive headers, but I still get unregistered_class exceptions.

I have looked around and it seems that whatever I can find is 1. either outdated, dealing with old versions of the library, or 2. works only for a simple one-file solution in which all the serializable classes are defined one after the other. Nothing I've found helps.

My solution at present consists of a project, compiled into a static library, that contains the core functionality with the basic archivable classes, and another test project that will eventually be fleshed out into a more concrete logic layer. Getting everything to work with boost::serialization is proving a nightmare. I'm almost tempted to write it myself.

Anyway, the class in question which raises the exception is defined in a header, which looks something like this:

#include <boost/serialization/assume_abstract.hpp>
#include <boost/serialization/serialization.hpp>
// Other includes...

namespace GameCore { class Component; }
//  Forward declare some boost::serialization functions that appear at the bottom.
// ...
BOOST_SERIALIZATION_ASSUME_ABSTRACT(GameCore::Component);

namespace GameCore
{
    // Some forward declares..

//////////////////////////////////////////////////////////////////////////
//  Base component type.
//////////////////////////////////////////////////////////////////////////
class Component : public Updatable, public Object
{
    friend class boost::serialization::access;  

protected:                                  
    template <typename Archive>                 
    friend void boost::serialization::serialize(Archive& archive, Component& object, const unsigned int version);   
    template <typename Archive> friend void boost::serialization::load_construct_data(Archive& archive, Component* t, const unsigned int version);  
    template <typename Archive> friend void boost::serialization::save_construct_data(Archive& archive, const Component* t, const unsigned int version);    

public:
    Component(GameObject& owner);
    virtual ~Component() = 0;

    // Irrelevant stuff..

    GameObject& gameObject;
    Transform* transform;
};
}
//  The component includes have to be placed here because it would otherwise create a cyclic inclusion when trying to compile the 
//  individual component classes, say, Transform, which would end up including itself.
#include "Transform.h"


namespace boost
{
    namespace serialization
    {
        template<class Archive>
        inline void save_construct_data(Archive& archive, const GameCore::Component* t, const unsigned int version)
        {
            archive << t->gameObject;
        }


    template<class Archive>
    inline void load_construct_data(Archive& archive, GameCore::Component* t, const unsigned int version)
    {
        //  Retrieve data from archive required to construct new instance.
        GameCore::GameObject owner;
        archive >> owner;

        //  Invoke inplace constructor to initialize instance of class.
        ::new(t)GameCore::Component(owner);
    }


    //////////////////////////////////////////////////////////////////////////
    //  Serialization function for save/load.
    //////////////////////////////////////////////////////////////////////////
    template <typename Archive>
    void serialize(Archive& archive, GameCore::Component& t, const unsigned int version)
    {
        archive & boost::serialization::base_object<GameCore::Object>(t);
        archive & boost::serialization::base_object<GameCore::Updatable>(t);
        archive & t.gameObject;
        archive & t.transform;
    }
}
}

That is one header file. Sorry for the verbosity. Its .cpp file starts like this:

#include "Component.h"

#include <boost/serialization/export.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
// Other includes...

BOOST_CLASS_EXPORT_GUID(GameCore::Component, "GameCore::Component");

// Class method definitions here.

The exception is raised when I try to archive an instance object that derives from Component , which itself is an abstract class. I'm archiving through a simple method defined in a different manager class:

std::ofstream outputFile(fileName);
boost::archive::text_oarchive outputArchive(outputFile);
outputArchive << objects;

where objects is a std::list of Object s. Object is the base class from which all things, including Component s, derive.

I apologize if this sounds convoluted, but there's only three layers of inheritance, and I believe I had a neat and effective architecture before thoughts of serialization crept in.

If you could help me get rid of the irrational unregistered_class exceptions I'll light a candle for your souls!

Update: Funny thing is, the exception isn't raised for all derived classes of Component .

After frying my neurones looking for an answer, I stumbled upon this line in the documentation:

Static Libraries and Serialization

Code for serialization of data types can be saved in libraries just as it can for the rest of the type implementation. This works well, and can save huge amount of compilation time. Only compile serialization definitions in the library. Explicitly instantiate serialization code for ALL archive classes you intend to use in the library. For exported types, only use BOOST_CLASS_EXPORT_KEY in headers. For exported types, only use BOOST_CLASS_EXPORT_IMPLEMENT in definitions compiled in the library. For any particular type, there should be only one file which contains BOOST_CLASS_EXPORT_IMPLEMENT for that type. This ensures that only one copy of serialization code will exist within the program. It avoids wasted space and the possibility of having different versions of the serialization code in the same program. Including BOOST_CLASS_EXPORT_IMPLEMENT in multiple files could result in a failure to link due to duplicated symbols or the throwing of a runtime exception.

Splitting BOOST_CLASS_EXPORT into BOOST_CLASS_EXPORT_KEY and BOOST_CLASS_EXPORT_IMPLEMENT seems to work.

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