Boost logo

Boost Users :

Subject: [Boost-users] Serialization: BOOST_CLASS_EXPORT changes between 1.38 and 1.52
From: Nathan Whitehorn (nwhitehorn_at_[hidden])
Date: 2013-02-07 09:39:48


I'm upgrading a large data analysis project from boost 1.38 to 1.52 (see
this 2008 Boostcon talk for details:
http://www.icecube.umd.edu/~troy/talks/icefishing.pdf). Everything has
gone remarkably smoothly, with a minimal degree of #if, except for one
thing: a change in the semantics of BOOST_CLASS_EXPORT.

The software is organized into a number of shared libraries each of
which have serializable classes that generally inherit from a shared
base class, through pointers to which the derived classes are almost
always [de]serialized to/from a custom archive type. When using 1.38,
the BOOST_CLASS_EXPORT directive was kept in the implementation file for
each serializable class.

This almost still works for 1.52 but can result in strange behavior that
took me two days to track down. Some of our classes would report through
unregistered class errors on [de]serialization. Which ones would depend
on circumstances, compiler version, linker, and operating system.

The reason turns out to be changes in handling of the class GUID. This
is associated to the pointer serializer by BOOST_CLASS_EXPORT -- but
also now apparently by the first instantiated code [de]serializing the
class through that archive directly based on the presence of a template
specialization of boost::serialization::guid<T>() currently in scope,
which is NULL by default. Once NULL is set as the GUID, it stays that
way, regardless of a proper BOOST_CLASS_EXPORT later. This occurred in
our case as a result of def_pickle() calls in boost.python bindings that
used the same classes and archive type.

This can be fixed by BOOST_CLASS_EXPORT_KEY in all appropriate header
files. Adding it is a sizeable amount of work (hundreds of classes) but
I'm more concerned the mechanism is very fragile in the case of
templates and I'm not sure what to do there. For example, we have a
generic serializable container. Any specialization of it needs to be
registered with BOOST_CLASS_EXPORT, which is fine, but anyone using that
specialization needs to also include a header file
BOOST_CLASS_EXPORT_KEY() in it for that particular specialization as
well. In other words, you can't just use container<Foo> and expect it to
work reliably and, moreover, if you use it *once* without having seen
the right in-scope macro, it will break serialization of that type
globally if you happen to have linked against a library that made this
mistake. Probably. Depending on initialization order.

So my questions:
1. Is it possible for things that would return GUIDs of NULL to try
harder and look in a global registry instead of silently breaking
things? This kind of global lookup was how 1.38 always worked and it
seems considerably less fragile.
2. Is there a way to handle BOOST_CLASS_EXPORT_KEY() sanely in the case
of templates without the risk of silent serialization failures -- in all
instances of that class -- that depend on global initialization order?
3. Is it possible to change the GUID set in the extended type info
object of a pointer_[i/o]serializer at runtime after the class has been
added to the export registry?
4. Are there any suggested mechanisms for local hacks, given that we
control the archive implementation, to implement 1-3 without changes to
boost?
-Nathan


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