Boost logo

Boost Users :

Subject: Re: [Boost-users] [serialization] Polymorphic serialization withpolymorphic archives problem...
From: Bogdan (bogdan.indy_at_[hidden])
Date: 2010-02-24 20:16:35


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).

 

==================================================

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);

    }

 

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 am looking forward to hearing your conclusions.

 

Thank you,

 

Bogdan



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