Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Put the serialization of a class into a DLL

I'm looking for a (working) example for externally serializing a class-structure in a DLL. Currently I'm not able to find any examples for that. The Boost documentation is just stating some macros, the forums and newsgroups are just discussing specific problems with their solutions.

So I'm asking for an example for (externally) serializing a class-structure like the following. Along with the class-code I added some code of mine for serializing (which does not work, see bottom for error-message).

class Foo
{
public:
    Foo() { number_ = 0; }
    virtual ~Foo() {}

    int getNumber() { return number_; }
    void setNumber( int var ) { number_ = var; }
private:
    int number_;
};

class Bar : public Foo
{
public:
    Bar() { doubleNumber_ = 0.0; }
    virtual ~Bar() {}

    double getDouble() { return doubleNumber_; }
    void setDouble( double var ) { doubleNumber_ = var; }

private:
    double doubleNumber_;
};

All what I've got so far is code like this:

serializeFoo.h

#ifndef _SERIALIZE_FOO_H_
#define _SERIALIZE_FOO_H_

#include "Foo.h"
#include <boost/serialization/split_free.hpp>
#include <boost/serialization/version.hpp>

namespace boost {
namespace serialization {

template <typename Archive>
void save(Archive& ar, const Foo& object, const unsigned int version)
{
    ar << object.getNumber();
}

template <typename Archive>
void load(Archive& ar, Foo& object, const unsigned int version)
{
    int number;
    ar >> number;
    object.setNumber(number);
}

}} //namespace brackets

BOOST_SERIALIZATION_SPLIT_FREE( Foo )

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/export.hpp>
BOOST_CLASS_EXPORT_KEY( Foo )

#endif //_SERIALIZE_FOO_H_

serializeFoo.cpp

#include "serializeFoo.h"
BOOST_CLASS_EXPORT_IMPLEMENT( Foo )

serializeBar.h:

#ifndef _SERIALIZE_BAR_H_
#define _SERIALIZE_BAR_H_

#include "Bar.h"
#include <boost/serialization/split_free.hpp>
#include <boost/serialization/version.hpp>

namespace boost {
namespace serialization {

template <typename Archive>
void save(Archive& ar, const Bar& object, const unsigned int version)
{
    ar << base_object<Foo>(object);
    ar << object.getDouble();
}

template <typename Archive>
void load(Archive& ar, Bar& object, const unsigned int version)
{
    double doubleNumber;
    ar >> doubleNumber;
    object.setDouble(doubleNumber);
}

}} //namespace brackets

BOOST_SERIALIZATION_SPLIT_FREE( Bar )

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/export.hpp>
BOOST_CLASS_EXPORT_KEY( Bar )

#endif //_SERIALIZE_BAR_H_

serializeBar.cpp:

#include "serializeBar.h"
BOOST_CLASS_EXPORT_IMPLEMENT( Bar )

The serialization-code goes into a DLL and should be used in another project using classes Foo and Bar. Everything compiles fine, but at runtime I get the message
unregistered class - derived class not registered or exported

So did I used the wrong macros? Do I miss a macro? Is the above code right or is there some kind of structural error? Perhaps this could be useful for a lot of other people too, I don't think that putting the serialization of a class into a DLL is very exotic...

like image 403
MOnsDaR Avatar asked Feb 08 '12 07:02

MOnsDaR


2 Answers

I ran into a similar issue recently, 3 years after this question was asked. I finally found out a workaround to solve it. In the example above.

  • Bar is a subclass of Foo, so it must be registered/exported;
  • serializeFoo.cpp instantiates a GUID template class to register/export Foo;
  • serializeBar.cpp instantiates a GUID template class to register/export Bar;
  • The rules to include all necessary archive types before exporting the class keys are respected;
  • Both translation units are linked together to create a DLL.

I assume in your exe, while you are trying to serialise a Foo* pointer pointing to a Bar object, you got the "unregistered class blahblah" error. This is because Boost.Serialization somehow does not properly generate a GUID for class Bar before the serialize function is called.

I don't know why this happens, but it seems that GUID is generated in a lazy way -- if none of the symbols from the translation unit serializeBar.cpp is used, none of the instantiation/initialization code defined in that translation unit will be performed -- that includes the class registration/exportation of Bar.

To prove that, you can try to use a (dummy) symbol in serializeBar.cpp (e.g. by calling a dummy function implemented in serializeBar.cpp) before calling any serialization function for Foo*. The issue should disappear.

Hope it helps.

like image 102
zzheng Avatar answered Oct 03 '22 06:10

zzheng


the test suite and demo distributed with the serialization library demonstrate exactly this facility. So first make sure that works. Then compare your example to it.

Robert Ramey

"Honestly, IMHO, at some points, Boost Serialization crosses the border of what is reliably possible with pure c++ build model w/o external tools..."

hmmmmmm - so it crosses the boarder as what's possible? You're pretty much correct in spirit though. Great effort was expended to implement everything that was considered necessary for such a package to be acceptable into boost.

RR

like image 26
Robert Ramey Avatar answered Oct 03 '22 07:10

Robert Ramey