问题
I'm trying to serialize a pointer to a polymorphic class Shape. So I need to use the BOOST_CLASS_EXPORT macro to define a GUID for each subclass. The problem: where to put it?
Let me show a minimal test case first:
shapes.hpp
#include <boost/serialization/access.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/export.hpp>
class Shape {
friend class boost::serialization::access;
template<typename Archive>
void serialize(Archive &ar, unsigned int const version) {
// nothing to do
}
public:
virtual ~Shape() { }
};
class Rect : public Shape {
friend class boost::serialization::access;
template<typename Archive>
void serialize(Archive &ar, unsigned int const version) {
ar & boost::serialization::base_object<Shape>(*this);
}
public:
virtual ~Rect() { }
};
#ifdef EXPORT_IN_HEADER
BOOST_CLASS_EXPORT(Rect)
#endif
export.cpp
#include <boost/serialization/export.hpp>
#include "shapes.hpp"
#ifdef EXPORT_IN_OBJECT
BOOST_CLASS_EXPORT(Rect)
#endif
main.cpp
#include <iostream>
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/export.hpp>
#include "shapes.hpp"
#ifdef EXPORT_IN_MAIN
BOOST_CLASS_EXPORT(Rect)
#endif
int main() {
Shape *shape = new Rect();
boost::archive::text_oarchive ar(std::cout);
ar << shape;
}
On gcc, I compile these with
g++ -omain main.cpp export.cpp -Wl,-Bstatic -lboost_serialization-mt -Wl,-Bdynamic -DEXPORT_IN_XXX
Here, export.cpp may look a bit silly. In my actual situation, it contains an enclosing class that uses the PIMPL idiom, and tries to serialize its (polymorphic) Shape implementation. The important point is: the BOOST_CLASS_EXPORT could be in a different object file than the code that invokes the serialization.
So here's the problem: where to use BOOST_CLASS_EXPORT? I have three options, which can be enabled using the EXPORT_IN_XXX macros.
EXPORT_IN_MAINworks, but is not what I want. The code invoking the serialization should not need to know about the implementation details of the PIMPL class.EXPORT_IN_OBJECTcompiles, but does not work: it results in aboost::archive::archive_exceptionwith the messageunregistered void cast. According to the documentation, this should be solved by serializing base classes usingboost::serialization::base_object, like I did, but it doesn't help.EXPORT_IN_HEADERdoes not even compile. The macroBOOST_CLASS_EXPORTexpands to a template specialization (which we'd like to be in the header file), but also to the definitiof of a static member therein. So I get a linker error about amultiple definition of 'boost::archive::detail::init_guid<Rect>::guid_initializer'.
If it matters, I'm using g++ 4.4.3 and Boost 1.40.
回答1:
Exporting Class Serialization of the Boost.Serialization docs (1.44.0) states the following:
BOOST_CLASS_EXPORTin the same source module that includes any of the archive class headers will instantiate code [...]Note that the implemenation of this functionality requires that the
BOOST_CLASS_EXPORTmacro appear after and the inclusion of any archive class headers for which code is to be instantiated. So, code that usesBOOST_CLASS_EXPORTwill look like the following:
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
... // other archives
#include "a.hpp" // header declaration for class a
BOOST_CLASS_EXPORT(a)
... // other class headers and exports
[...] Including
BOOST_CLASS_EXPORTin the "a.hpp" header itself as one would do with other serialization traits will make it difficult or impossible to follow the rule above regarding inclusion of archive headers beforeBOOST_CLASS_EXPORTis invoked. This can best be addressed by usingBOOST_CLASS_EXPORT_KEYin the header declarations andBOOST_CLASS_EXPORT_IMPLEMENTin the class definition file.
回答2:
I ended up putting all the serialization code in a header s11n.h that is included from the CPP file that invokes the serialization. Essentially, the EXPORT_IN_MAIN scenario I sketched above, but with the BOOST_CLASS_EXPORT macro invocations in a different file.
This only works as long as only one compilation unit includes s11n.h, of course, so although it works for now, it's no real solution...
回答3:
You can use EXPORT_IN_OBJECT but the file that contains BOOST_CLASS_EXPORT must also include all the archive hpp files that plan to use.
This is because the BOOST_CLASS_EXPORT macro registers the derived type information which each archive it thinks you will use (implicitly determined based upon which archives you have included.)
In your example, use EXPORT_IN_OBJECT but also add #include to export.cpp.
In our code, we created archives.hpp that contains the archives we use and include it where ever we need to use BOOST_CLASS_EXPORT. (That way we have a single official list of archives.)
The downside is that we need to rebuild everything when we decide to use a new archive type, but we found that much easier to use than the polymorphic archive support.
回答4:
Check out this older thread.
http://lists.boost.org/boost-users/2005/01/9390.php
回答5:
you can use and unique BOOST_CLASS_EXPORT_GUID() for each .cpp and add it only in the .cpp. not the .h
回答6:
This problem drove me insane until I realized that my base class was not polymorphic. In other words, it never used the keyword "virtual" anywhere. Because I didn't need polymorphic behavior.
Here is how I fixed it:
- I just slapped the keyword "virtual" on some random method in my base class.
In my derived class's .cpp file, I added the following:
#include <boost/serialization/export.hpp> BOOST_CLASS_EXPORT(testnamespace::derivedclass)
This is all that I had to do.
来源:https://stackoverflow.com/questions/3396330/where-to-put-boost-class-export-for-boostserialization