Re: [Boost-users] [serialization] Polymorphic serialization withpolymorphic archives problem...

Robert Ramey
Martin Lederhilger wrote:
Hello Robert, hello Bogdan,
I have quite the same problem (Exception multiple_code_instantiation
thrown in basic_serializer_map.cpp at line 48) as Bogdan. It can be
reproduced by changing
the pointer type from polymorphic_base to polymorphic_derived2 in the
original test_dll_exported.cpp example, which comes with the library.
I think the problem is that when oa << BOOST_SERIALIZATION_NVP(rb2);
is called, that the system registers an type in oserializer.hpp, which
leads to creation of the singletons also in the executeable.
Ahhhh - a very useful hint. So the rule would be that if a class
is polymorphic is to be serialized through a pointer, it should ONLY
be done through a base class pointer? That is, if ALL polymorphic
base classes are abstract - this problem will never occur?
I'll have to think about this.
I have this problem when serializing a shared_ptr<A> in class B in
B.dll to an object of class A in A.dll.
I tried to simply comment out this check, but it seems that I get
problems with tracking later. I have a class hierarchy like this:
C derives from B derives from A. A has a weak_ptr<A> to itself
(something like boost::enable_shared_from_this). If I serialize an
object of type C via a base pointer of type B the serialization walks
like this: C::serialize, B::serialize, A::serialize, and again
C::serialize (with a wrong this pointer - and it should not do that).
Hmmm - why should it not do that? You may have a cycle - but
the library handles that. Seems unrelated to the other problem.
Maybe my second problem depends on the first one. I hope that my
report can be of help.
Thanks in advance for your answers,
And thanks for your useful information.
Martin Lederhilger
Hello Robert,
On your suggestion I have run a few tests. I hope they help:
I commented out the registration macro associated to the base class in
ExportDll.dll:
- //BOOST_CLASS_EXPORT_IMPLEMENT(polymorphic_base)
To make the example more realistic I modified the inheritance hierarchy as
follows:
class polymorphic_base{};
class polymorphic_derived1 : public polymorphic_base{};
class polymorphic_derived2 : public polymorphic_derived1{};
I added one integer data member to polymorphic_derived1 and
polymorphic_derived2.
Here are the results:
==================================================
Polymorphic serialization through a pointer to polymorphic_base WORKS AS
EXPECTED:
// Save code -----------------------------
polymorphic_base *rb0 = new polymorphic_derived1(100);
polymorphic_base *rb1 = new polymorphic_derived1(10);
polymorphic_base *rb2 = new polymorphic_derived2(10,20);
oa << BOOST_SERIALIZATION_NVP(rb0);
oa << BOOST_SERIALIZATION_NVP(rb1);
oa << BOOST_SERIALIZATION_NVP(rb2);
// Load code -----------------------------
polymorphic_base *rb0 = NULL;
polymorphic_base *rb1 = NULL;
polymorphic_base *rb2 = NULL;
ia >> BOOST_SERIALIZATION_NVP(rb0);
ia >> BOOST_SERIALIZATION_NVP(rb1);
ia >> BOOST_SERIALIZATION_NVP(rb2);
The serialized content is presented below:
- for polymorphic_xml_[io]archive
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>

Bogdan wrote:
Robert Ramey
writes: Martin Lederhilger wrote:
Hello Robert, hello Bogdan,
I have quite the same problem (Exception multiple_code_instantiation thrown in basic_serializer_map.cpp at line 48) as Bogdan. It can be reproduced by changing the pointer type from polymorphic_base to polymorphic_derived2 in the original test_dll_exported.cpp example, which comes with the library. I think the problem is that when oa << BOOST_SERIALIZATION_NVP(rb2); is called, that the system registers an type in oserializer.hpp, which leads to creation of the singletons also in the executeable.
Ahhhh - a very useful hint. So the rule would be that if a class is polymorphic is to be serialized through a pointer, it should ONLY be done through a base class pointer? That is, if ALL polymorphic base classes are abstract - this problem will never occur?
I'll have to think about this.
I have this problem when serializing a shared_ptr<A> in class B in B.dll to an object of class A in A.dll.
I tried to simply comment out this check, but it seems that I get problems with tracking later. I have a class hierarchy like this: C derives from B derives from A. A has a weak_ptr<A> to itself (something like boost::enable_shared_from_this). If I serialize an object of type C via a base pointer of type B the serialization walks like this: C::serialize, B::serialize, A::serialize, and again C::serialize (with a wrong this pointer - and it should not do that).
Hmmm - why should it not do that? You may have a cycle - but the library handles that. Seems unrelated to the other problem.
Maybe my second problem depends on the first one. I hope that my report can be of help.
Thanks in advance for your answers,
And thanks for your useful information.
Martin Lederhilger
Hello Robert,
On your suggestion I have run a few tests. I hope they help:
I commented out the registration macro associated to the base class in ExportDll.dll:
- //BOOST_CLASS_EXPORT_IMPLEMENT(polymorphic_base)
To make the example more realistic I modified the inheritance hierarchy as follows:
class polymorphic_base{}; class polymorphic_derived1 : public polymorphic_base{}; class polymorphic_derived2 : public polymorphic_derived1{};
I added one integer data member to polymorphic_derived1 and polymorphic_derived2.
Here are the results:
================================================== Polymorphic serialization through a pointer to polymorphic_base WORKS AS EXPECTED:
// Save code ----------------------------- polymorphic_base *rb0 = new polymorphic_derived1(100); polymorphic_base *rb1 = new polymorphic_derived1(10); polymorphic_base *rb2 = new polymorphic_derived2(10,20);
oa << BOOST_SERIALIZATION_NVP(rb0); oa << BOOST_SERIALIZATION_NVP(rb1); oa << BOOST_SERIALIZATION_NVP(rb2);
// Load code ----------------------------- polymorphic_base *rb0 = NULL; polymorphic_base *rb1 = NULL; polymorphic_base *rb2 = NULL;
ia >> BOOST_SERIALIZATION_NVP(rb0); ia >> BOOST_SERIALIZATION_NVP(rb1); ia >> BOOST_SERIALIZATION_NVP(rb2);
The serialized content is presented below:
- for polymorphic_xml_[io]archive
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> <!DOCTYPE boost_serialization>
<rb0 class_id="1" class_name="polymorphic_derived1" tracking_level="1" version="0" object_id="_0"> 100 </rb0> <rb1 class_id_reference="1" object_id="_1">10 </rb1> <rb2 class_id="2" class_name="polymorphic_derived2" tracking_level="1" version="0" object_id="_2">20 10 </rb2>- for polymorphic_text_[io]archive
22 serialization::archive 7 1 20 polymorphic_derived1 1 0 0 0 0 100 1 1 10 2 20 polymorphic_derived2 1 0 2 3 20 10
================================================== Polymorphic serialization through a pointer to polymorphic_derived1 (i.e. the class in the middle of the hierarchy) FAILS WITH THE SAME EXCEPTION thrown about multiple registration (see the beginning of this thread).
This would be expected as polymorphic_derived1 and polymorphic_derived2 are explicitly referred to in the mainline so that would endup instantiting the extended_type_info for these types in the main line as well as in the DLL. Hence the error.
================================================== What is worrisome though, isomorphic serialization of polymorphic_derived1 as an object followed by polymorphic serialization through a pointer to the base class FAILS WITH ACCESS VIOLATION:
// Save code ----------------------------- polymorphic_derived1 rb0(100); polymorphic_base *rb1 = new polymorphic_derived1(10); polymorphic_base *rb2 = new polymorphic_derived2(10,20);
oa << BOOST_SERIALIZATION_NVP(rb0); oa << BOOST_SERIALIZATION_NVP(rb1); oa << BOOST_SERIALIZATION_NVP(rb2);
// Load code ----------------------------- polymorphic_derived1 rb0; polymorphic_base *rb1 = NULL; polymorphic_base *rb2 = NULL;
ia >> BOOST_SERIALIZATION_NVP(rb0); ia >> BOOST_SERIALIZATION_NVP(rb1); ia >> BOOST_SERIALIZATION_NVP(rb2);
The code above fails in basic_iarchive.cpp(line 469) with access violation (bpis is 0).
if(! tracking){ bpis_ptr->load_object_ptr(ar, t, co.file_version); }
Of course it should never fail with an access violation. I'll look into it.
The serialized content is presented below:
- using polymorphic_xml_[io]archive
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> <!DOCTYPE boost_serialization>
<rb0 class_id="0" tracking_level="0" version="0"> 100 </rb0> <rb1 class_id_reference="0" object_id="_0">10 </rb1> <rb2 class_id="2" class_name="polymorphic_derived2" tracking_level="1" version="0" object_id="_1">20 10 </rb2>- using polymorphic_text_[io]archive
22 serialization::archive 7 0 0 0 0 100 0 0 10 2 20 polymorphic_derived2 1 0 1 2 20 10
================================================== Isomorphic serialization of a class not related to the hierarchy as an object followed by polymorphic serialization through a pointer to the base class WORKS AS EXPECTED.
I'm not sure what the above means. Here is what I believe. any usage of an exported class will instantiate extended_type_info instance variables for that class. If the classes are exported from multiple modules, we'll get code instantiated in multiple modules and a trap. On one hand, this trap prevents the code with the same signature being instanticiated in different modules. On the other hand, it takes extra care to avoid this and may not always be possible - at least without a lot of extra work. I'm thinking about how to resolve this conflict. Robert Ramey
participants (2)
-
Bogdan
-
Robert Ramey