Boost logo

Boost :

From: David Tonge (david.tonge_at_[hidden])
Date: 2004-03-12 07:04:39


Robert,

I've made a small project which replicates the problems I was having
yesterday. I think that part of the problem was that my solution for
exporting the guids for shared_ptrs was like this...

  typedef boost::detail::sp_counted_base_impl<T*, ....> T_shared_ptr;
  BOOST_CLASS_EXPORT(T_shared_ptr);

...and if the typedef wasn't in scope where the streaming occurred then
the streaming system didn't recognize that the
sp_counted_base_impl<T*,...> was a T_shared_ptr. Anyway, I've resolved
that by making a more complicated macro for exporting the guids, which
doesn't use any typedefs. That's included in the attached archive as
hack_shared_ptr.h. It isn't possible simply to do...

  BOOST_CLASS_EXPORT(boost::detail::sp_counted_base_impl<T*, ....>)

...because that contains a comma, and the preprocessor thinks you're
passing two parameters to a macro which expects only one. Anyway, I
think the new macro (HACK_SP_BOOST_CLASS_EXPORT(T)) avoids that problem.

Now to my other problem. I wanted to investigate the serialization
tools in the context of a larger project. My habit is to define my
class interfaces in header files, like base_class.h, and provide their
implementations in source files like base_class.cpp. I like my headers
to be lightweight and include the minimum number of other header files
in order that compilation times don't get out of hand.

I had been including the BOOST_CLASS_EXPORT(T) commands in the headers
but that means I have to include all of the archive headers, and
export.hpp in every header, and that makes for slow compilations. My
hope is that I can include all of those only in the implementation .cpp
and put the BOOST_CLASS_EXPORT(T) there. I was also worried that if I
included the BOOST_CLASS_EXPORT(T) in the header then every other .cpp
which included that header would also try to register the guid for T -
surely an unnecessary replication of effort.

Having done all of this I found that my program would work fine if
everything existed in a single EXE. However, if I implement them as a
DLL containing my base_class and derived_class implementations and an
EXE, which uses these classes, then things fail.

In the attached .ZIP there is a VC7.1 solution which builds three
different projects:

  single_project Contains all of my example source code, and builds
a
                     single .EXE which streams two
shared_ptr<base_class>
                     to file and then loads them back. One of the
                     pointers contains a derived_class.

  dll_implemetation Contains implementations of base_class and
                     derived_class. It also contains the
                     BOOST_CLASS_EXPORT commands for those classes.
This
                     project builds a DLL which exports these classes.
 
  exe_using_dll Contains just the main() function. It should do
the
                     same as single_project does as the main() is the
same.

Single_project works fine. exe_using_dll fails when it tries to save
the pointer to the derived_class. The failure is an unregistered_class
exception.

I've stepped through the code for exe_using_dll and I can see that the
failure occurs when it tries to get extended type information for the
derived_class (at line 297 of oserializer.hpp). However, I know that
the class has been registered by the guid_initializer (at line 130 of
export.hpp) because I put a breakpoint there, and saw initialization
happen for base_class, derived_class and the shared_ptr versions of
both.

My suspicion is that the problem is caused by the serialization library
using a static library, rather than a DLL. If the BOOST_CLASS_EXPORT
commands updated a list contained in the static library then there would
be one instance of this list statically linked into my DLL, and another
in my EXE. Thus, the registration occurring in the DLL wouldn't affect
the list used in the EXE.

If this is the case then it's going to be quite inconvenient. It would
mean one would have to BOOST_CLASS_EXPORT every class in every DLL where
an instance of it (or a shared_pointer which might contain it) might be
saved. If that were the case then I'd advocate making
boost_serialization into a DLL, rather than a static library.

I'd be grateful if you could take a look at my example, and let me know
if there is something I can do to resolve my problems.

Regards,

David Tonge


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk