Boost logo

Boost :

Subject: Re: [boost] [Serialization] (Commented) assertion when using types in multiple DLLs on Windows (Ticket #3934 and #4394)
From: Martin B. (0xCDCDCDCD_at_[hidden])
Date: 2011-12-14 03:19:26


On 14.12.2011 09:03, Martin B. wrote:
> On 13.12.2011 18:22, Robert Ramey wrote:
>> Martin B. wrote:
>>> [Serialization] (Commented) assertion when using types in multiple
>> (...) (...)
>>> ## Question: Solutions?
>>> (...)
>> I would like to see you invest some more effort to see
>> exactly where the extra registration comes from.
>
> Well, see my call-stack above and I'll dump a sourcecode sketch below.
> This does reproduce the thing for me, but other that ignoring the assert
> (upgrading to boost 1.48) I haven't tried any approaches yet.
>

Okay. Now, for this my testproject, I have been able to make it "just
work" without the assertion by:

1. Removing the Types.cpp file from the executable (this will obviously
initially give an unresolved external warning for Derived::* members)

2.) Make Derived a DLL export class, that is:
     class DLL_API Derived : ...
with the usual
     #ifdef DLL_EXPORTS
     #define DLL_API __declspec(dllexport)
     #else
     #define DLL_API __declspec(dllimport)
     #endif

To my surprise it compiles, links, and runs correctly. (And the type is
only registered once, namely from the DLL.)

Now I'll just have to check if this solution can be applicable for our
real projects, where we currently use BOOST_CLASS_EXPORT() instead of
the split versions and we have a multitude of derived classes.

So maybe the assertion made sense after all. (Though I think this should
be configurable on a type by type basis should it ever be reenabled.)

cheers,
Martin

p.s: Leaving sorcecode quote:

>
> ps: Sourcecode (files separated by ++++++++)
>
> a) 2 Projects, one executable and one DLL that is "statically" used by
> the exe.
>
> EXE:
> Types.cpp
> main.cpp
>
> DLL:
> Types.cpp
> dll_main.cpp
>
> b) An abstract base class and a derived class that are used in the EXE
> as well as in the DLL, but are compiled and linked for both.
>
> c) The exe uses these types in serialization and the DLL as well.
>
> ++++++++
> // Types.h
> #pragma warning( disable : 4250 )
> #define BOOST_SERIALIZATION_DYN_LINK
> #include <boost/archive/text_oarchive.hpp>
> #include <boost/archive/text_iarchive.hpp>
> #include <boost/serialization/scoped_ptr.hpp>
> #include <boost/serialization/export.hpp>
>
> class Base
> {
> public:
> virtual ~Base() {}
>
> virtual void DoStuff() = 0;
>
> private:
> friend class boost::serialization::access;
>
> template<class Archive>
> void serialize(Archive & ar, const unsigned int file_version);
> };
> BOOST_SERIALIZATION_ASSUME_ABSTRACT(Base);
>
>
> struct SData {
> boost::scoped_ptr<Base> obj;
> };
> BOOST_CLASS_TRACKING(SData, boost::serialization::track_never);
>
> namespace boost {
> namespace serialization {
>
> template<class Archive>
> void serialize(Archive & ar, SData & data, const unsigned int version)
> {
> assert(version == 0);
> ar & data.obj;
> }
>
> } // namespace serialization
> } // namespace boost
>
>
> class Derived : virtual public Base {
> public:
> Derived();
>
> virtual void DoStuff();
>
> private:
> int m_number;
>
> private:
> friend class boost::serialization::access;
>
> template<class Archive>
> void serialize(Archive & ar, const unsigned int file_version);
> };
>
> BOOST_CLASS_EXPORT_KEY(Derived);
>
> ++++++++
> // Types.cpp
> #include "Types.h"
>
> template<class Archive>
> void Base::serialize(Archive & ar, const unsigned int file_version)
> { /*empty*/ }
>
>
> BOOST_CLASS_EXPORT_IMPLEMENT(Derived);
>
> Derived::Derived()
> : m_number(42)
> { }
>
> void Derived::DoStuff() {
> std::cout << static_cast<void*>(this) << " - Derived::DoStuff:\n" << "
> current value = " << m_number << "\n";
> ++m_number;
> std::cout << " new value = " << m_number << "\n";
> }
>
> template<class Archive>
> void Derived::serialize(Archive & ar, const unsigned int version)
> {
> ar & boost::serialization::base_object<Base>(*this);
>
> assert(version == 0);
> ar & m_number;
> }
>
> +++++++++
> main.cpp (executable)
> #include ...
> #include "Types.h"
>
> int main() {
> SData d1;
> d1.obj.reset(new Derived());
> d1.obj->DoStuff();
>
> std::ostringstream out_buf;
> boost::archive::text_oarchive out_archive(out_buf);
> out_archive << d1;
> const std::string data = out_buf.str();
>
> std::istringstream in_buf(data);
> boost::archive::text_iarchive in_archive(in_buf);
> SData d2;
> in_archive >> d2;
>
> d2.obj->DoStuff();
> d1.obj->DoStuff();
> }
>
>
> ++++++++
> // dll_main.cpp
> #include ...
> #include "Types.h"
>
> void dll_fn_that_uses_serialization() {
> SData d1;
> d1.obj.reset(new Derived());
> d1.obj->DoStuff();
>
> std::ostringstream out_buf;
> boost::archive::text_oarchive out_archive(out_buf);
> out_archive << d1;
> const std::string data = out_buf.str();
>
> std::istringstream in_buf(data);
> boost::archive::text_iarchive in_archive(in_buf);
> SData d2;
> in_archive >> d2;
>
> d2.obj->DoStuff();
> d1.obj->DoStuff();
> }
>


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