Boost logo

Boost Users :

Subject: [Boost-users] SERIALIZE: Registering derived templete classes serialized via base ptr
From: Unger, Jörg (joerg.unger_at_[hidden])
Date: 2016-02-17 07:35:34


I'm trying to serialize a derived class via a base ptr using boost serialize. The example to illustrate the problem (without templates) is as follows

//****************** Main.cpp **********************
#include <fstream>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>

#include "Derived.h"

int main(int argc, char* argv[])
{
    std::string fileName = "Out.txt";

    Derived myDerived;
    Base* myBasePtr = &myDerived;

    //myDerived.foo();

    // serialize it as txt
    std::ofstream ofs(fileName.c_str(), std::ios_base::binary );
    boost::archive::text_oarchive ota ( ofs, std::ios::binary );
    //ota & boost::serialization::make_nvp(std::string("directly derived").c_str(), myDerived);;
    ota & boost::serialization::make_nvp(std::string("via base ptr").c_str(), myBasePtr);;

    return 0;
}
//***********************************************

//*************** Base.h *************************
#pragma once

#include <boost/serialization/access.hpp>
#include <boost/serialization/export.hpp>

class Base
{
    friend class boost::serialization::access;
public:
    Base(){};

    virtual ~Base(){};

    template<class Archive>
    void serialize(Archive & ar, const unsigned int version)
    {};

};

BOOST_CLASS_EXPORT_KEY(Base)
//***********************************************

//**************** Derived.h **********************
#pragma once
#include <boost/serialization/access.hpp>
#include <boost/serialization/export.hpp>

#include "Base.h"

class Derived : public Base
{
    friend class boost::serialization::access;

public:
    Derived(){};

    void foo();

    template<class Archive>
    void serialize(Archive & ar, const unsigned int version);
};

BOOST_CLASS_EXPORT_KEY(Derived)

//***********************************************

//**************** Derived.cpp ********************
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>

#include "Derived.h"

//Derived::Derived()
//{}

void Derived::foo()
{
}

// serializes the class
template void Derived::serialize(boost::archive::text_oarchive & ar, const unsigned int version);
template void Derived::serialize(boost::archive::text_iarchive & ar, const unsigned int version);
template<class Archive>
void Derived::serialize(Archive & ar, const unsigned int version)
{
    ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base);
}

BOOST_CLASS_EXPORT_IMPLEMENT(Derived)

//***********************************************

When compiling the above code and linking the object files, everything works fine. When I combine everything in a library (in this example it is essentially only Derived.o) and link the main file with the library, I get an error

what(): unregistered class - derived class not registered or exported

The problem seems to be that the registration in the linked library is not activated. The problem is simplified here, because in our implementation, the derived class is essentially a template class that does not have any cpp-files. We have just added another otherwise empty cpp file with the registration of all possible instantiations of the class.

There are several possibilities to solve the problem

· The macro BOOST_CLASS_EXPORT_IMPLEMENT(Derived) could be moved to the main.cpp. This workaround is not my preferred options, since the registration has to be done in every main file we want to use the library for.

· The macro BOOST_CLASS_EXPORT_IMPLEMENT(Derived) could be moved to the Base.cpp (the constructor for the base class has to be implemented in this file as well). This is another option, but this requires the header files of the derived classes to be included in Base.cpp, which is not convenient either.

· Serialize one object of the derived class before serialization through the pointer, but that's only a workaround. (see the commented line in Main.cpp)

· Call the foo method in Main.cpp. Surprisingly, this does not depend on whether the foo function is implemented in Derived.cpp, but also if it is called in Main.cpp. Surprisingly, if "myDerived.foo();" in Main.cpp is uncommented the program works fine, which is something I do not understand. It seems that the registration is only performed, if one of the functions in this cpp file is actually called, or am I wrong?

· Implement the constructor of Derived in Derived.cpp. This approach works fine for the current example (somehow similar to the previous solution). However, in our case, Derived is a template and thus the constructor can't be implemented in the cpp file.

· Another option is to always link the main file with the library and the object file Derived.o, but this is also not a convenient option.

· Finally, a manual registration with register_type is possible. This could be moved to a separate subroutine that is always called in different main files.

What is the recommended way of registering derived template classes that are serialized through a base ptr within a library.

Best regards,
Jörg F. Unger



Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net