Boost logo

Boost Users :

Subject: [Boost-users] problem deserializing to base class pointer
From: Shipa (msipetic_at_[hidden])
Date: 2011-09-01 08:36:20


I have a strange problem.

I searched through the list and modified my initial code
quite a bit but cannot seem to get this to work. Serialization
seems fine, but deserialization to base pointer in particular
doesn't seem to work correctly (I am getting instance of base
class inside).

The example below is canonical version of a much more complex
case I was working with, involving shared_ptr and template
classes, but it boiled down (for now) to this:

A.h
----------------------------------------------------
#pragma once

#include "boost/serialization/serialization.hpp"
#include "boost/shared_ptr.hpp"

class A
{
public:
        int t;
        A():t(0){};

        //friend std::ostream& operator<<(std::ostream& os, const A& a);

        virtual ~A(){ };

        friend class boost::serialization::access;
        template<class Archive>
        void serialize(Archive & ar, const unsigned int version)
        {
                ar & t;
        }
};

std::ostream& operator<<(std::ostream& os, const A& a)
{
        return os << "A: t = " << a.t << std::endl;
}

typedef boost::shared_ptr<A> APtr;
----------------------------------------------------

B.h
----------------------------------------------------

#pragma once

#include "boost/serialization/serialization.hpp"
#include "boost/shared_ptr.hpp"

class B: public A
{
public:
        int m;
        B():A(),m(0){};
        ~B(){};

        //friend std::ostream& operator<<(std::ostream& os, const B& b);

        friend class boost::serialization::access;
        template<class Archive>
        void serialize(Archive & ar, const unsigned int version)
        {
                ar & boost::serialization::base_object<A>(*this);
                ar & m;
        }
};

std::ostream& operator<<(std::ostream& os, const B& b)
{
        return os << "B: t = "<< b.t << "; m = "<< b.m << std::endl;
}

typedef boost::shared_ptr<B> BPtr;

----------------------------------------------------------------

Test.cpp
----------------------------------------------------------------
#include "stdafx.h"
#include "boost/shared_ptr.hpp"

#include "boost/serialization/shared_ptr.hpp"
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/export.hpp>

#include <istream>
#include <ostream>
#include <fstream>

#include "A.h"
#include "B.h"

BOOST_CLASS_EXPORT(A)
BOOST_CLASS_EXPORT(B)

boost::archive::text_iarchive* GetiArchiveAndRegister(std::ifstream& f)
{
        boost::archive::text_iarchive* ar=
          new boost::archive::text_iarchive(f);
// ar->register_type(static_cast<A *>(NULL));
// ar->register_type(static_cast<B *>(NULL));
        return ar;
}

boost::archive::text_oarchive* GetoArchiveAndRegister(std::ofstream& f)
{
        boost::archive::text_oarchive* ar=new boost::archive::text_oarchive(f);
// ar->register_type(static_cast<A*>(NULL));
// ar->register_type(static_cast<B*>(NULL));
        return ar;
}

int _tmain(int argc, _TCHAR* argv[])
{
        A* a=new A();
        a->t=1;

        B* b=new B();
        b->t=2;
        b->m=1;

        A* c=new B();
        c->t=2;
        
        std::ofstream f1("c:\\a");
        boost::archive::text_oarchive* oa1=GetoArchiveAndRegister(f1);
        *oa1 & a;
        f1.close();

        std::ofstream f2("c:\\b");
        boost::archive::text_oarchive* oa2=GetoArchiveAndRegister(f2);
        *oa2 & b;
        f2.close();

        std::ofstream f3("c:\\c");
        boost::archive::text_oarchive* oa3=GetoArchiveAndRegister(f3);
        *oa3 & c;
        f3.close();

//deserializes fine
        std::ifstream f4("c:\\a");
        boost::archive::text_iarchive* oa4=GetiArchiveAndRegister(f4);
        *oa4 & a;
        f4.close();

//deserializes an instance of A
        std::ifstream f5("c:\\b");
        boost::archive::text_iarchive* oa5=GetiArchiveAndRegister(f5);
        *oa5 & a;
        f5.close();

//deserializes fine
        std::ifstream f6("c:\\c");
        boost::archive::text_iarchive* oa6=GetiArchiveAndRegister(f6);
        *oa6 & a;
        f6.close();

//deserializes fine
        std::ifstream f7("c:\\b");
        boost::archive::text_iarchive* oa7=GetiArchiveAndRegister(f7);
        *oa7 & b;
        f7.close();

        std::ifstream f8("c:\\c");
        boost::archive::text_iarchive* oa8=GetiArchiveAndRegister(f8);
//runtime error: vector subscript out of range on the next line
        *oa8 & b;
        f8.close();

        return 0;
}
------------------------------------------------------------------

deserializations of f5 and f8 are controversial.

I tried exchanging BOOST_CLASS_EXPORT calls with register_type
call (commented out in GetiArchiveAndRegister and
GetoArchiveAndRegister), and when that is done both
serialization and deserialization finish correctly.

I tried changing the order of includes, moving BOOST_CLASS_EXPORT
around, etc. This version is what I'm settled for as the correct
one.

What am I doing wrong? Can anybody help?


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