Boost logo

Boost Users :

Subject: Re: [Boost-users] [Boost Serialization] Problem serializing derived class declared in DLL
From: François Mauger (mauger_at_[hidden])
Date: 2011-04-05 18:12:42


Hi,

>>>kmdarkmaster a écrit :
> Dear Boost community,
>
> My problem is simple : I need to serialize a derived class (named Plugin) of
> a c++ class (named Base) in my main program.
>
> The derived class Plugin is declared in a DLL which is load explicitely
> during execution.
>
> I tried to use the macro BOOST_CLASS_EXPORT_GUID (as in the doc), this works
> perfectly if the derived class is in the main execution,
i think you should read:
it works perfectly if *BOOST_CLASS_EXPORT_GUID* is in the main execution.
you can still put your derived class wherever you want !

> but will give me an
> exception
what exception ?

> if the derived class is in the plugin DLL.
>
It looks like an issue I've met a few weeks ago.
After investigation (note may be I'm wrong but I can only report of my
understanding which is far
to be good !) I now believe it is NOT possible
to scatter such serialization export bits in different places (DLL vs
executable, DLL vs DLL).
It is because, as far as I understand the concept, the "export" mechanism
you mentioned is implemented in the DLL object scope (probably using
some static 'local' dictionary instantiated in the DLL scope or the
executable scope, depending of the user).
You can imagine such case: your base class is registered in the DLL but your
Daughter class is registered at the level of the executable object scope
: thus there is no
way to make them communicate about their relationship. Both dictionaries
(one per instantiation unit) acts
in different words and know only one subset of the serializable classes
to be used in your executable.

The solution for me was to make sure that ALL my serialization code,
together with
the associated export stuff mechanism ,is instantiated in one and only
one place: the executable.
At least, I do not pollute my DLLs with some serialization related
instantiations
that may be I won't use in some of my other executables.

In your case, I think you could step back to the previous approach where
all serialization stuff is instantiated in the executable.
The alternative is to probably to move your xml_archive ser/deser code
in some resource implemented in the DLL and promote some reader and
writer classes for XML archives
as an element of your DLL, the later being the unique place to safely
embed the problematic bits.
I'm afraid there is not intermediate.

You may find this "feature" annoying or even disappointing.
However, it is not a bug ! It is a conceptual choice made by Robert for
the Serialization lib.
It is not as bad as you could think at a first glance. IMHO it is a good
design not to have
a central export registration 'manager'. Otherwise, such a beast would
encourage developpers to
add large amount of instantiated serialization/export code in any DLL
for large collection
of serializable classes, with some consequence to
possibly end up with lots of unused serialization code being linked for
nothing. I also think this would break
the "template" spirit and probably could lead to performance issues if
thousands of inherited
classes from several independant DLLs were registered in one single
central place.

With the current implementation of the lib,
users are forced to do a careful analysis of what they need from the
executable
in term of base-pointer oriented serialization. They have to manage
to instantiate the only serialization bits strictly necessary for their I/O.
The corresponding template code that will be generated is thus minimal.

I recommend you not to use the *EXPORT* macro in your class header file,
as well as instantiation code
of the template "serialize" methods of your class. Use some kind of .ipp
files for that to be included
from your main program when it makes sense, and not by default in your DLL.
I find this technique rather sane (of course it needs extra care, but
that does not hurt, isn't it ?).
Note also that if you don't want to use some "my_serialization.ipp"
file, you can provide an alternative one,
with different implementation of the template serialization code.

I hope you find find these comments useful.
Note I'm not completely sure they make sense in your situation. In the
absence of more details,
it is only a guess, probably not very understandable... sorry for that.
Also I'm not sure to understand well the pb. I probably have a rather
partial view on it.

Hope some gurus will be able to raise the tone of this technical debate.
I would enjoy to read more about
this topic.

cheers

frc

--
> Forgive me if the problem is too obvious, this is my first time using Boost
> and I'm still a big noob in c++.
>
> Here is my code : 
>
> IN THE MAIN EXECUTION : 
>
> Class Base (parent class) : 
>
> Base.h :
> #pragma once;
> #include "boost\serialization\access.hpp"
> #include <boost\serialization\nvp.hpp>
>
> class Base
> {
> private:
>     friend class boost::serialization::access;
>     template
>     void serialize(Archive & ar, const unsigned int version){}
> public:
> 	int a, b;
> 	Base();
> 	virtual ~Base()
> 	{
> 	}
> 	virtual void func()= 0;	 // this is an abstract base class
> }
>
> Base.cpp:
>
> #include "StdAfx.h"
> #include "Base.h"
>
> Base::Base(){
> 	a=0;
> 	b=0;
> }
>
>
> IN THE DLL (loaded explicitely)
>
> Class Plugin (Child Class) :
>
> Plugin.h:
>
> #pragma once
> #include "boost\serialization\access.hpp"
> #include <boost\serialization\nvp.hpp>
> #include "boost\serialization\export.hpp"
> #include "Base.h"
>
> class Plugin: public Base
> {
> private:
>
>     friend class boost::serialization::access;
>     template
>     void serialize(Archive & ar, const unsigned int version){
> 		ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base);
> 		ar & BOOST_SERIALIZATION_NVP(a);
> 		ar & BOOST_SERIALIZATION_NVP(b);
>      }
>
> public:
> 	virtual void func();
> };
>
> BOOST_CLASS_EXPORT_GUID(Plugin, "Plugin")
>
> Plugin.cpp:
>
> #include "StdAfx.h"
> #include "Plugin.h"
>
> void Plugin::func(){
> 	a= 5;
> 	b= 6;
> }
>
>
>
> THE MAIN FUNCTION (IN THE MAIN EXECUTION):
>
> .......................................
>
> 	HINSTANCE hinst= LoadLibrary(L"monDLLdynamique.dll");
> 	if (hinst)
> 	{
> 		CreatePlugin ctor= (CreatePlugin)GetProcAddress(hinst, "CreatePlugin");
> 		Base *test= ctor();
>
> 			std::ofstream ofs3("FichierPointeursDerivedDLL.xml");
> 			{
> 				boost::archive::xml_oarchive oa(ofs3);
> 				oa << BOOST_SERIALIZATION_NVP(test);
> 			}
> 			ofs3.close();
>
> 		delete test;  // calls Plugin's dtor 
>
> 		FreeLibrary(hinst);
> 	}
>
> ............................................
>
>
> Any help will be very very appreciated !!!
> Thanks
>
> --
> View this message in context: http://boost.2283326.n4.nabble.com/Boost-Serialization-Problem-serializing-derived-class-declared-in-DLL-tp3428913p3428913.html
> Sent from the Boost - Users mailing list archive at Nabble.com.
> _______________________________________________
> Boost-users mailing list
> Boost-users_at_[hidden]
> http://lists.boost.org/mailman/listinfo.cgi/boost-users
>
>   
-- 
François Mauger 
  Groupe "Interactions Fondamentales et Nature du Neutrino"
  NEMO-3/SuperNEMO Collaboration
LPC Caen-CNRS/IN2P3-UCBN-ENSICAEN
Département de Physique -- Université de Caen Basse-Normandie
Adresse/address:
  Laboratoire de Physique Corpusculaire de Caen (UMR 6534)
  ENSICAEN 
  6, Boulevard du Marechal Juin
  14050 CAEN Cedex
  FRANCE
Courriel/e-mail: mauger_at_[hidden] 
Tél./phone:      02 31 45 25 12 / (+33) 2 31 45 25 12
Fax:             02 31 45 25 49 / (+33) 2 31 45 25 49

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