Boost logo

Boost Users :

Subject: Re: [Boost-users] [serialization] Polymorphicserialization withpolymorphic archives problem...
From: Robert Ramey (ramey_at_[hidden])
Date: 2010-02-25 02:25:35


Bogdan wrote:
> Robert Ramey <ramey <at> rrsd.com> 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>
> <boost_serialization signature="serialization::archive" version="7">
> <rb0 class_id="1" class_name="polymorphic_derived1"
> tracking_level="1" version="0" object_id="_0">
> <polymorphic_base class_id="0" tracking_level="0"
> version="0"></polymorphic_base>
> <m_d1_>100</m_d1_>
> </rb0>
> <rb1 class_id_reference="1" object_id="_1">
> <polymorphic_base></polymorphic_base>
> <m_d1_>10</m_d1_>
> </rb1>
> <rb2 class_id="2" class_name="polymorphic_derived2"
> tracking_level="1" version="0" object_id="_2">
> <polymorphic_derived1 object_id="_3">
> <polymorphic_base></polymorphic_base>
> <m_d1_>20</m_d1_>
> </polymorphic_derived1>
> <m_d2_>10</m_d2_>
> </rb2>
> </boost_serialization>
>
> - 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>
> <boost_serialization signature="serialization::archive" version="7">
> <rb0 class_id="0" tracking_level="0" version="0">
> <polymorphic_base class_id="1" tracking_level="0"
> version="0"></polymorphic_base>
> <m_d1_>100</m_d1_>
> </rb0>
> <rb1 class_id_reference="0" object_id="_0">
> <polymorphic_base></polymorphic_base>
> <m_d1_>10</m_d1_>
> </rb1>
> <rb2 class_id="2" class_name="polymorphic_derived2"
> tracking_level="1" version="0" object_id="_1">
> <polymorphic_derived1 object_id="_2">
> <polymorphic_base></polymorphic_base>
> <m_d1_>20</m_d1_>
> </polymorphic_derived1>
> <m_d2_>10</m_d2_>
> </rb2>
> </boost_serialization>
>
> - 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


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