Discussion:
Guide to using serialization macro BOOST_CLASS_EXPORT
Bill Lear
2005-01-07 13:27:19 UTC
Permalink
I am having some trouble understanding just where I am supposed to
put BOOST_CLASS_EXPORT macros for classes I write --- in class
headers (.h), in class implementation files (.cc), in applications
that plan to save/load through base pointers?

I have base class B, from which I derive lots of classes. I tried
putting the BOOST_CLASS_EXPORT in the header files of each class, but
soon found that this resulted in link-time errors due to multiple
definitions.

So, I moved the macro to an implementation (.cc) file, creating it if
necessary, with the form:

#include "Derived.h"

BOOST_CLASS_EXPORT(Derived);

The problem with this is that I have an application that does this:

#include "Base.h"
#include "Derived.h" // fails with or without this

void foo() {
Base* b = load("file.xml");
}

Now, since no instance of Derived is appearing in my application,
the linker apparently does not pull in the (expanded) macro, and when
I run the application, I get an unregistered class exception.

So, I removed all of the macros from the implementation files and
put them in a header (again), that is designed for applications that
may want to serialize (any) of my derived classes:

#include "Base.h"
#include "Derived.h"
#include "BoostExports.h"

void foo() {
Base* b = load("file.xml");
}

and this works fine.

So my question is this: is this what other people do, or are there other
solutions that people prefer?

The problem with the above is that if I have 20 derived classes and
put all the macro exports in BoostExports.h, even if my application
may only be interested in a smaller subset, I have to pull in 20
header files each time, and I had hoped to avoid that. This is not a
terrible thing, I just wondered what other approaches there might be.


Bill
Robert Ramey
2005-01-07 18:58:13 UTC
Permalink
Post by Bill Lear
I am having some trouble understanding just where I am supposed to
put BOOST_CLASS_EXPORT macros for classes I write --- in class
headers (.h), in class implementation files (.cc), in applications
that plan to save/load through base pointers?
The whole concept behind BOOST_CLASS_EXPORT has been problematic for me for
a couple of reasons. As a result, the confusion you cite is a real one.

My intention was that:

a) BOOST_CLASS_EXPORT be part of the header file for a particular class.
b) A typical program would look like:

#include <boost/archive/text_oarchive.hpp>
// other archives used.

#inlcude "my_class.hpp"
// other classes from my library. many of which will use EXPORT

main(){
...
// the BOOST_CLASS_EXPORT will guarentee that code required for
serialization for derived classes is
// included in the program even though it is not explicitly referred to
by name. Without
// BOOST_CLASS_EXPORT, a smart compiler/linker will conclude this code
is never called
// and throw it away on linking.
...
}

c) BOOST_CLASS_EXPORT emits code for each archive template for the class
specified. This could contribute to code bloat

d) This system requires that the #include for archives preceed those for
serialization implemenations. A violation of this requirement should result
in a compile time failure with and error message and point to code with a
comment explaining the problem.

I've toyed with re-implementing this to get around problems created by
two-phase lookup but managed to address these in another way so I don't
expect this explanation to change in the near future.
Post by Bill Lear
I have base class B, from which I derive lots of classes. I tried
putting the BOOST_CLASS_EXPORT in the header files of each class, but
soon found that this resulted in link-time errors due to multiple
definitions.
I'll look into this. It might be fixable. It was my intention to permit
this.

Note that including BOOST_CLASS_EXPORT to programs which don't in fact
serialize through a base class pointer may instanciate code that is in fact
never called. I'll look into this as well.

Robert Ramey
Bill Lear
2005-01-07 19:54:05 UTC
Permalink
Post by Robert Ramey
...
The whole concept behind BOOST_CLASS_EXPORT has been problematic for me for
a couple of reasons. As a result, the confusion you cite is a real one.
I settled on the following that a friend suggested, which seems to
work.

In my serialization/util.h file, I have the following:

template <class T>
void save(const T* t, const std::string& filename) { ... }

template <class T>
T* load(const std::string& filename) { ... }

at the bottom of this file, I have the following:

namespace dummy { struct bogus { static int bogus_method(); }; }

// force linking with util.cc
static int bogus_variable = dummy::bogus::bogus_method();

in serialization/util.cc, I have:

#include <serialization/util.h>

// expensive include which we wish to relegate to one one source file.
#include <AllDerived.h>

// the trigger method that forces others to link with this module
int dummy::bogus::bogus_method() { return 0;}

The AllDerived.h file has includes for all my headers and all the
BOOST_CLASS_EXPORT macros.

In my application code, I do this:

#include <Base.h>
#include <serialization/util.h>

and it all works flawlessly. I am spared from including the headers
for my derived classes, and the accompanying export macros. The save
and load routines work as expected.


Bill
Robert Ramey
2005-01-07 20:06:33 UTC
Permalink
I see how this would work. I would hope my method in the previous post would
work as well.

Robert Ramey
Post by Bill Lear
Post by Robert Ramey
...
The whole concept behind BOOST_CLASS_EXPORT has been problematic for
me for a couple of reasons. As a result, the confusion you cite is
a real one.
I settled on the following that a friend suggested, which seems to
work.
template <class T>
void save(const T* t, const std::string& filename) { ... }
template <class T>
T* load(const std::string& filename) { ... }
namespace dummy { struct bogus { static int bogus_method(); }; }
// force linking with util.cc
static int bogus_variable = dummy::bogus::bogus_method();
#include <serialization/util.h>
// expensive include which we wish to relegate to one one source
file. #include <AllDerived.h>
// the trigger method that forces others to link with this module
int dummy::bogus::bogus_method() { return 0;}
The AllDerived.h file has includes for all my headers and all the
BOOST_CLASS_EXPORT macros.
#include <Base.h>
#include <serialization/util.h>
and it all works flawlessly. I am spared from including the headers
for my derived classes, and the accompanying export macros. The save
and load routines work as expected.
Bill
Jim Lear
2005-01-07 20:28:50 UTC
Permalink
_______________________________________________
Boost-users mailing list
Boost-***@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/boost-users

Loading...