Boost logo

Boost :

From: Pascal Kesseli (pascal_kesseli_at_[hidden])
Date: 2007-12-27 18:30:54


Hi folks
 
Currently I’m having quite some trouble with the boost serialization library. Take the following classes as given:
 
ProtocolFactory.h:
#ifndef PROTOCOLFACTORY_H_
#define PROTOCOLFACTORY_H_
 
#include <boost/serialization/access.hpp>
#include <boost/serialization/is_abstract.hpp>
#include <boost/shared_ptr.hpp>
 
class Meter;
typedef boost::shared_ptr<Meter> MeterPtr;
class MeteringProtocol;
typedef boost::shared_ptr<MeteringProtocol> MeteringProtocolPtr;
 
class ProtocolFactory {
public:
    ProtocolFactory();
    virtual ~ProtocolFactory();
    virtual MeteringProtocolPtr getNewProtocolInstance(Meter *const) const = 0;
    virtual MeteringProtocolPtr
            getNewProtocolInstance(const MeterPtr &) const = 0;
private:
    friend class boost::serialization::access;
    template<class archive> void serialize(archive &, const unsigned int) {
    }
};
 
BOOST_IS_ABSTRACT(ProtocolFactory);
 
typedef boost::shared_ptr<ProtocolFactory> ProtocolFactoryPtr;
 
#endif /*PROTOCOLFACTORY_H_*/
 
 
ProtocolFactory.cpp
#include "ProtocolFactory.h"
 
ProtocolFactory::ProtocolFactory() {
}
 
ProtocolFactory::~ProtocolFactory() {
}
 
 
Iec1107OverSerialFactory.h
#ifndef IEC1107OVERSERIALFACTORY_H_
#define IEC1107OVERSERIALFACTORY_H_
 
#include "ProtocolFactory.h"
 
class Iec1107OverSerialFactory : public ProtocolFactory {
public:
    Iec1107OverSerialFactory();
    virtual ~Iec1107OverSerialFactory();
    virtual MeteringProtocolPtr getNewProtocolInstance(Meter *const) const;
    virtual MeteringProtocolPtr getNewProtocolInstance(const MeterPtr &) const;
private:
    friend class boost::serialization::access;
    template<class archive> void serialize(archive &, const unsigned int);
};
 
#include "Iec1107OverSerialFactory.inc"
 
typedef boost::shared_ptr<Iec1107OverSerialFactory> Iec1107OverSerialFactoryPtr;
 
#endif /*IEC1107OVERSERIALFACTORY_H_*/
 
 
 
Iec1107OverSerialFactory.inc:
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/nvp.hpp>
 
BOOST_CLASS_EXPORT(Iec1107OverSerialFactory) // Boost must include Serialization info for this class even if its not directly referencd (e.g. by its base class)
 
template<class Archive> void Iec1107OverSerialFactory::serialize(Archive &ar, const unsigned int version) {
      using boost::serialization::make_nvp;
      ar & make_nvp("ProtocolFactory", boost::serialization::base_object<ProtocolFactory>(*this));
}
 
 
Iec1107OverSerialFactory.cpp:
#include "Iec1107OverSerialFactory.h"
#include "Iec1107OverSerial.h"
#include "../Meter.h"
#include "MeteringProtocol.h"
 
using namespace boost;
 
Iec1107OverSerialFactory::Iec1107OverSerialFactory() {
}
 
Iec1107OverSerialFactory::~Iec1107OverSerialFactory() {
}
 
MeteringProtocolPtr Iec1107OverSerialFactory::getNewProtocolInstance(
            Meter *const target) const {
      return MeteringProtocolPtr(new Iec1107OverSerial(target));
}
 
MeteringProtocolPtr Iec1107OverSerialFactory::getNewProtocolInstance(
            const MeterPtr &target) const {
      return MeteringProtocolPtr(new Iec1107OverSerial(target));
}
 
 
MeteringProtocolCompoisteFactory.h
#ifndef METERINGPROTOCOLCOMPOSITEFACTORY_H_
#define METERINGPROTOCOLCOMPOSITEFACTORY_H_
 
#include "ProtocolFactory.h"
#include <vector>
 
class MeteringProtocolCompositeFactory : public ProtocolFactory {
public:
    MeteringProtocolCompositeFactory(const std::vector<ProtocolFactoryPtr> &);
    virtual ~MeteringProtocolCompositeFactory();
    virtual MeteringProtocolPtr getNewProtocolInstance(Meter *const) const;
    virtual MeteringProtocolPtr getNewProtocolInstance(const MeterPtr &) const;
    const std::vector<ProtocolFactoryPtr> &getFactories() const;
private:
    std::vector<ProtocolFactoryPtr> factories;
    friend class boost::serialization::access;
    template<class archive> void serialize(archive &, const unsigned int);
};
 
#include "MeteringProtocolCompositeFactory.inc"
 
typedef boost::shared_ptr<MeteringProtocolCompositeFactory>
        MeteringProtocolCompositeFactoryPtr;
 
#endif /*METERINGPROTOCOLCOMPOSITEFACTORY_H_*/
 
 
MeteringProtocolCompoisteFactory.inc
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/nvp.hpp>
 
BOOST_CLASS_EXPORT(MeteringProtocolCompositeFactory) // Boost must include Serialization info for this class even if its not directly referencd (e.g. by its base class)
 
namespace boost {
namespace serialization {
template<class Archive> inline void save_construct_data(Archive &ar, const MeteringProtocolCompositeFactory *pf, const unsigned int version) {
      using boost::serialization::make_nvp;
      ar & make_nvp("IncludedProtocols", pf->getFactories());
}
template<class Archive> inline void load_construct_data(Archive &ar, MeteringProtocolCompositeFactory *pf, const unsigned int version) {
      using boost::serialization::make_nvp;
      std::vector<ProtocolFactoryPtr> factories;
      ar & make_nvp("IncludedProtocols", factories);
      
      ::new(pf)MeteringProtocolCompositeFactory(factories);
}
}
}
template<class Archive> void MeteringProtocolCompositeFactory::serialize(Archive &ar, const unsigned int version) {
      using boost::serialization::make_nvp;
      ar & make_nvp("ProtocolFactory", boost::serialization::base_object<ProtocolFactory>(*this));
}
 
 
MeteringProtocolCompositeFactory.cpp:
#include "MeteringProtocolCompositeFactory.h"
#include "MeteringProtocolComposite.h"
#include <iterator>
 
using namespace std;
 
MeteringProtocolCompositeFactory::MeteringProtocolCompositeFactory(
        const vector<ProtocolFactoryPtr> &factories) :
    factories(factories) {
}
 
MeteringProtocolCompositeFactory::~MeteringProtocolCompositeFactory() {
}
 
MeteringProtocolPtr MeteringProtocolCompositeFactory::getNewProtocolInstance(
        Meter *const target) const {
    vector<MeteringProtocolPtr> protocols;
    for (vector<ProtocolFactoryPtr>::const_iterator it = factories.begin(); it
            != factories.end(); ++it) {
        protocols.push_back((*it)->getNewProtocolInstance(target));
    }
    return MeteringProtocolPtr(new MeteringProtocolComposite(protocols));
}
 
MeteringProtocolPtr MeteringProtocolCompositeFactory::getNewProtocolInstance(
        const MeterPtr &target) const {
    vector<MeteringProtocolPtr> protocols;
    for (vector<ProtocolFactoryPtr>::const_iterator it = factories.begin(); it
            != factories.end(); ++it) {
        protocols.push_back((*it)->getNewProtocolInstance(target));
    }
    return MeteringProtocolPtr(new MeteringProtocolComposite(protocols));
}
 
const std::vector<ProtocolFactoryPtr> &MeteringProtocolCompositeFactory::getFactories() const {
    return factories;
}
 
 
MeterType.h:
#ifndef METERTYPE_H_
#define METERTYPE_H_
 
#include <boost/serialization/access.hpp>
#include <boost/shared_ptr.hpp>
#include <string>
#include <vector>
 
class ProtocolFactory;
typedef boost::shared_ptr<ProtocolFactory> ProtocolFactoryPtr;
 
class MeterType {
public:
    MeterType(const std::string &, const std::vector<std::string> &,
            const ProtocolFactoryPtr &);
    virtual ~MeterType();
    const std::string &getTypeName() const;
    const std::vector<std::string> &getRequestedDataItems() const;
    const ProtocolFactoryPtr &getSupportedProtocols() const;
private:
    MeterType();
    std::string typeName;
    std::vector<std::string> requestedDataItems; // include Data IDs like 1.8.1, standardized for all metering protocls (I hope :)
    // TODO: Create ProtocolFactoryComposite, including a serialization
    // TODO: Serialize supportedProtcols and add to constructor
    ProtocolFactoryPtr supportedProtocols;
 
    friend class boost::serialization::access;
    template<class archive> void serialize(archive &, const unsigned int);
};
 
#include "MeterType.inc"
 
typedef boost::shared_ptr<MeterType> MeterTypePtr;
 
#endif /*METERTYPE_H_*/
 
 
MeterType.inc:
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/vector.hpp>
#include <iostream>
 
namespace boost {
namespace serialization {
template<class Archive> inline void save_construct_data(Archive &ar, const MeterType *t, const unsigned int version) {
      using boost::serialization::make_nvp;
      ar & make_nvp("TypeName", t->getTypeName());
      ar & make_nvp("RequestedDataItems", t->getRequestedDataItems());
      ar & make_nvp("SupportedProtocols", t->getSupportedProtocols());
}
template<class Archive> inline void load_construct_data(Archive &ar, MeterType *t, const unsigned int version) {
      using boost::serialization::make_nvp;
      std::string typeName;
      std::vector<std::string> requestedDataItems;
      ProtocolFactoryPtr supportedProtocols;
      ar & make_nvp("TypeName", typeName);
      ar & make_nvp("RequestedDataItems", requestedDataItems);
      ar & make_nvp("SupportedProtocols", supportedProtocols);
            
      ::new(t)MeterType(typeName, requestedDataItems, supportedProtocols);
}
}
}
template<class Archive> void MeterType::serialize(Archive &ar, const unsigned int version) {
}
 
 
MeterType.cpp:
#include "MeterType.h"
 
using namespace std;
 
MeterType::MeterType(void) {
}
 
MeterType::MeterType(const string &typeName,
        const vector<string> &requestedDataItems,
        const ProtocolFactoryPtr &supportedProtocols) :
    typeName(typeName), requestedDataItems(requestedDataItems),
            supportedProtocols(supportedProtocols) {
}
 
MeterType::~MeterType() {
}
 
const string &MeterType::getTypeName() const {
    return typeName;
}
 
const vector<string> &MeterType::getRequestedDataItems() const {
    return requestedDataItems;
}
 
const ProtocolFactoryPtr &MeterType::getSupportedProtocols() const {
    return supportedProtocols;
}
 
 
 
Phew. Quite a list, I know :) . Anyway, to serialize these classes, I wrote the following code:
 
    {
        ofstream ofs("testIt.xml");
        archive::xml_oarchive oxml(ofs);
        oxml << serialization::make_nvp("supportedProtocols", iec1107);
    }
    ProtocolFactoryPtr newProtocolFactory;
    ifstream ifs("testIt.xml");
    archive::xml_iarchive ixml(ifs);
    ixml >> serialization::make_nvp("supportedProtocols", newProtocolFactory);
 
which, however, throws an assert-failure in „basic_iarchive.cpp“ at line 390. Uncommenting that line and recompiling allows me to fully and correctly execute the above code. However, when trying this:
 
    {
        ofstream ofs("testIt.xml");
        archive::xml_oarchive oxml(ofs);
        oxml << serialization::make_nvp("ZMD120", zmd120);
    }
    MeterTypePtr newType;
    ifstream ifs("testIt.xml");
    archive::xml_iarchive ixml(ifs);
    ixml >> serialization::make_nvp("ZMD120", zmd120);
 
The Program crashes with a segmentation fault. Using Insight, i found the very line this happens: It’s in „MeterType.inc“ at line 22:
„ar & make_nvp(„SupportedProtocols“, supportedProtocols);
 
Since I imagine this to be more or less exactly the same code as I executed before, without the MeterType class, I’m not quite sure why this should fail. Anyway, can anyone lend me a hand here? Firstly, why would the assertion error occur? And why does serializing ProtocolFactoryPtr one time work and another time fail?
 
Thank you for any help and best regards
Kessi
 
_________________________________________________________________
Drück deine Gefühle aus! Hol dir 30 GRATIS Emoticons für den Windows Live Messenger!
http://get.live.com


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk