Boost logo

Boost Users :

Subject: [Boost-users] http://www.boost.org/doc/libs/1_53_0/libs/serialization/example/demo.cpp does not work properly when using polymorphic xml archive
From: Fadhel (fadhelatig_at_[hidden])
Date: 2013-06-14 12:04:02


Hi all,

I used
http://www.boost.org/doc/libs/1_53_0/libs/serialization/example/demo.cpp
file as a first introduction to boost serialization. I would like to use
polymorphic archives with XML serilialization format (to avoid having
the templatized version). I edited this example and run it. Writing the
data has worked fine -- except for the base_class serialization which
needed an nvp -- but reading it causes a memory/segmentation fault
problem. The same error happens with a binary archive. Using a text
archive works fine. I'm new to boost serialization and debugging the
code did not help me a lot.

Is there anything specific to the serialization of base classes or
abstract classes with the polymorphic XML format which needs to be handled?
Or is this related to the serialization of pointers to the base class.

Thanks for your help.
Best Regards,
Fadhel BA

Here is the code I'm using: ( I removed some comments to make the code
shorter)

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
// demo.cpp
#include <cstddef> // NULL
#include <iomanip>
#include <iostream>
#include <fstream>
#include <string>

#include <boost/archive/polymorphic_iarchive.hpp>
#include <boost/archive/polymorphic_oarchive.hpp>
#include <boost/archive/polymorphic_xml_iarchive.hpp>
#include <boost/archive/polymorphic_xml_oarchive.hpp>
#include <boost/archive/polymorphic_binary_iarchive.hpp>
#include <boost/archive/polymorphic_binary_oarchive.hpp>
#include <boost/archive/polymorphic_text_iarchive.hpp>
#include <boost/archive/polymorphic_text_oarchive.hpp>

#include <boost/serialization/base_object.hpp>
#include <boost/serialization/utility.hpp>
#include <boost/serialization/list.hpp>
#include <boost/serialization/assume_abstract.hpp>
#include <boost/serialization/nvp.hpp>

/////////////////////////////////////////////////////////////
// gps coordinate
//
// llustrates serialization for a simple type
//
class gps_position
{
     friend std::ostream & operator<<(std::ostream &os, const
gps_position &gp);
     friend class boost::serialization::access;
     int degrees;
     int minutes;
     float seconds;

     void serialize(boost::archive::polymorphic_oarchive &ar, const
unsigned int /* file_version */) const {
         ar << BOOST_SERIALIZATION_NVP(degrees);
         ar << BOOST_SERIALIZATION_NVP(minutes);
         ar << BOOST_SERIALIZATION_NVP(seconds);
     }

     void serialize(boost::archive::polymorphic_iarchive &ar, const
unsigned int /* file_version */) {
         ar >> BOOST_SERIALIZATION_NVP(degrees);
         ar >> BOOST_SERIALIZATION_NVP(minutes);
         ar >> BOOST_SERIALIZATION_NVP(seconds);
     }
public:
     // every serializable class needs a constructor
     gps_position(){};
     gps_position(int _d, int _m, float _s) :
         degrees(_d), minutes(_m), seconds(_s)
     {}

};

std::ostream & operator<<(std::ostream &os, const gps_position &gp)
{
     return os << ' ' << gp.degrees << (unsigned char)186 << gp.minutes
<< '\'' << gp.seconds << '"';
}

/////////////////////////////////////////////////////////////
// One bus stop
//
// illustrates serialization of serializable members
//

class bus_stop
{
     friend class boost::serialization::access;
     friend std::ostream & operator<<(std::ostream &os, const bus_stop &gp);
     virtual std::string description() const = 0;
     gps_position latitude;
     gps_position longitude;

     void serialize(boost::archive::polymorphic_oarchive &ar, const
unsigned int version) const
     {
         ar << BOOST_SERIALIZATION_NVP(latitude);
         ar << BOOST_SERIALIZATION_NVP(longitude);
     }

     void serialize(boost::archive::polymorphic_iarchive &ar, const
unsigned int version)
     {
         ar >> BOOST_SERIALIZATION_NVP(latitude);
         ar >> BOOST_SERIALIZATION_NVP(longitude);
     }
protected:
     bus_stop(const gps_position & _lat, const gps_position & _long) :
         latitude(_lat), longitude(_long)
     {}
public:
     bus_stop(){}
     virtual ~bus_stop(){}
};

BOOST_SERIALIZATION_ASSUME_ABSTRACT(bus_stop)

std::ostream & operator<<(std::ostream &os, const bus_stop &bs)
{
     return os << bs.latitude << bs.longitude << ' ' << bs.description();
}

/////////////////////////////////////////////////////////////
// Several kinds of bus stops
//
// illustrates serialization of derived types
//
class bus_stop_corner : public bus_stop
{
     friend class boost::serialization::access;
     std::string street1;
     std::string street2;
     virtual std::string description() const
     {
         return street1 + " and " + street2;
     }

     void serialize(boost::archive::polymorphic_oarchive &ar, const
unsigned int version) const
     {
         // save/load base class information
         ar << boost::serialization::make_nvp("base",
boost::serialization::base_object<bus_stop>(*this));
         ar << BOOST_SERIALIZATION_NVP(street1);
         ar << BOOST_SERIALIZATION_NVP(street2);;
     }

     void serialize(boost::archive::polymorphic_iarchive &ar, const
unsigned int version)
     {
         // save/load base class information
         ar >> boost::serialization::make_nvp("base",
boost::serialization::base_object<bus_stop>(*this));
         ar >> BOOST_SERIALIZATION_NVP(street1);
         ar >> BOOST_SERIALIZATION_NVP(street2);
     }

public:
     bus_stop_corner(){}
     bus_stop_corner(const gps_position & _lat, const gps_position & _long,
         const std::string & _s1, const std::string & _s2
     ) :
         bus_stop(_lat, _long), street1(_s1), street2(_s2)
     {
     }
};

class bus_stop_destination : public bus_stop
{
     friend class boost::serialization::access;
     std::string name;
     virtual std::string description() const
     {
         return name;
     }

     void serialize(boost::archive::polymorphic_oarchive &ar, const
unsigned int version) const
     {
         ar << boost::serialization::make_nvp("base",
boost::serialization::base_object<bus_stop>(*this));
         ar << BOOST_SERIALIZATION_NVP(name);
     }

     void serialize(boost::archive::polymorphic_iarchive &ar, const
unsigned int version)
     {
         ar >> boost::serialization::make_nvp("base",
boost::serialization::base_object<bus_stop>(*this));
         ar >> BOOST_SERIALIZATION_NVP(name);
     }
public:

     bus_stop_destination(){}
     bus_stop_destination(
         const gps_position & _lat, const gps_position & _long, const
std::string & _name
     ) :
         bus_stop(_lat, _long), name(_name)
     {
     }
};

/////////////////////////////////////////////////////////////
// a bus route is a collection of bus stops
//
// illustrates serialization of STL collection templates.
//
// illustrates serialzation of polymorphic pointer (bus stop *);
//

class bus_route
{
     friend class boost::serialization::access;
     friend std::ostream & operator<<(std::ostream &os, const bus_route
&br);
     typedef bus_stop * bus_stop_pointer;
     std::list<bus_stop_pointer> stops;

     void serialize(boost::archive::polymorphic_oarchive &ar, const
unsigned int version) const
     {
         // in this program, these classes are never serialized directly
but rather
         // through a pointer to the base class bus_stop. So we need a
way to be
         // sure that the archive contains information about these
derived classes.
         //ar.template register_type<bus_stop_corner>();
         ar.register_type(static_cast<bus_stop_corner *>(NULL));
         //ar.template register_type<bus_stop_destination>();
         ar.register_type(static_cast<bus_stop_destination *>(NULL));
         // serialization of stl collections is already defined
         // in the header
         ar << BOOST_SERIALIZATION_NVP(stops);
     }

     void serialize(boost::archive::polymorphic_iarchive &ar, const
unsigned int version)
     {

         ar.register_type(static_cast<bus_stop_corner *>(NULL));
         ar.register_type(static_cast<bus_stop_destination *>(NULL));
         // in the header
         ar >> BOOST_SERIALIZATION_NVP(stops);
     }
public:
     bus_route(){}
     void append(bus_stop *_bs)
     {
         stops.insert(stops.end(), _bs);
     }
};

std::ostream & operator<<(std::ostream &os, const bus_route &br)
{
     std::list<bus_stop *>::const_iterator it;
     // note: we're displaying the pointer to permit verification
     // that duplicated pointers are properly restored.
     for(it = br.stops.begin(); it != br.stops.end(); it++){
         os << '\n' << std::hex << "0x" << *it << std::dec << ' ' << **it;
     }
     return os;
}

/////////////////////////////////////////////////////////////
// a bus schedule is a collection of routes each with a starting time

class bus_schedule
{
public:
     // note: this structure was made public. because the friend
declarations
     // didn't seem to work as expected.
     struct trip_info
     {
         void serialize(boost::archive::polymorphic_oarchive &ar, const
unsigned int file_version) const
         {
             // in versions 2 or later
             if(file_version >= 2)
                 // read the drivers name
                 ar << BOOST_SERIALIZATION_NVP(driver);
             // all versions have the follwing info
             ar << BOOST_SERIALIZATION_NVP(hour);
             ar << BOOST_SERIALIZATION_NVP(minute);
         }

          void serialize(boost::archive::polymorphic_iarchive &ar, const
unsigned int file_version)
         {
             // in versions 2 or later
             if(file_version >= 2)
                 // read the drivers name
                 ar >> BOOST_SERIALIZATION_NVP(driver);
             // all versions have the follwing info
             ar >> BOOST_SERIALIZATION_NVP(hour);
             ar >> BOOST_SERIALIZATION_NVP(minute);
         }

         // starting time
         int hour;
         int minute;
         // only after system shipped was the driver's name added to the
class
         std::string driver;

         trip_info(){}
         trip_info(int _h, int _m, const std::string &_d) :
             hour(_h), minute(_m), driver(_d)
         {}
     };
private:
     friend class boost::serialization::access;
     friend std::ostream & operator<<(std::ostream &os, const
bus_schedule &bs);
     friend std::ostream & operator<<(std::ostream &os, const
bus_schedule::trip_info &ti);
     std::list<std::pair<trip_info, bus_route *> > schedule;

     void serialize(boost::archive::polymorphic_oarchive &ar, const
unsigned int version) const
     {
         ar << BOOST_SERIALIZATION_NVP(schedule);
     }

     void serialize(boost::archive::polymorphic_iarchive &ar, const
unsigned int version)
     {
         ar >> BOOST_SERIALIZATION_NVP(schedule);
     }
public:
     void append(const std::string &_d, int _h, int _m, bus_route *_br)
     {
         schedule.insert(schedule.end(), std::make_pair(trip_info(_h,
_m, _d), _br));
     }
     bus_schedule(){}
};

BOOST_CLASS_VERSION(bus_schedule, 2)

std::ostream & operator<<(std::ostream &os, const
bus_schedule::trip_info &ti)
{
     return os << '\n' << ti.hour << ':' << ti.minute << ' ' <<
ti.driver << ' ';
}
std::ostream & operator<<(std::ostream &os, const bus_schedule &bs)
{
     std::list<std::pair<bus_schedule::trip_info, bus_route *>
>::const_iterator it;
     for(it = bs.schedule.begin(); it != bs.schedule.end(); it++){
         os << it->first << *(it->second);
     }
     return os;
}

void save_schedule(const bus_schedule &s, const char * filename){
     // make an archive
     std::ofstream ofs(filename);
     boost::archive::polymorphic_xml_oarchive oa(ofs);
     oa << s;
}

void
restore_schedule(bus_schedule &s, const char * filename)
{
     // open the archive
     std::ifstream ifs(filename);
     boost::archive::polymorphic_xml_iarchive ia(ifs);
     // restore the schedule from the archive
     ia >> s;
}

int main(int argc, char *argv[])
{
     // make the schedule
     bus_schedule original_schedule;

     // fill in the data
     // make a few stops
     bus_stop *bs0 = new bus_stop_corner(
         gps_position(34, 135, 52.560f),
         gps_position(134, 22, 78.30f),
         "24th Street", "10th Avenue"
     );
     bus_stop *bs1 = new bus_stop_corner(
         gps_position(35, 137, 23.456f),
         gps_position(133, 35, 54.12f),
         "State street", "Cathedral Vista Lane"
     );
     bus_stop *bs2 = new bus_stop_destination(
         gps_position(35, 136, 15.456f),
         gps_position(133, 32, 15.300f),
         "White House"
     );
     bus_stop *bs3 = new bus_stop_destination(
         gps_position(35, 134, 48.789f),
         gps_position(133, 32, 16.230f),
         "Lincoln Memorial"
     );

     // make a routes
     bus_route route0;
     route0.append(bs0);
     route0.append(bs1);
     route0.append(bs2);

     // add trips to schedule
     original_schedule.append("bob", 6, 24, &route0);
     original_schedule.append("bob", 9, 57, &route0);
     original_schedule.append("alice", 11, 02, &route0);

     // make aother routes
     bus_route route1;
     route1.append(bs3);
     route1.append(bs2);
     route1.append(bs1);

     // add trips to schedule
     original_schedule.append("ted", 7, 17, &route1);
     original_schedule.append("ted", 9, 38, &route1);
     original_schedule.append("alice", 11, 47, &route1);

     // display the complete schedule
     std::cout << "original schedule";
     std::cout << original_schedule;

     std::string filename("C:/Dev/XML");
     filename += "/demofile.xml";

     // save the schedule
     save_schedule(original_schedule, filename.c_str());

     // ... some time later
     // make a new schedule
     bus_schedule new_schedule;

     std::cout << "\n\nstarting restored schedule";
     restore_schedule(new_schedule, filename.c_str());

     // and display
     std::cout << "\nrestored schedule";
     std::cout << new_schedule;
     // should be the same as the old one. (except for the pointer values)

     delete bs0;
     delete bs1;
     delete bs2;
     delete bs3;
     return 0;
}


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