Boost logo

Boost Users :

Subject: Re: [Boost-users] binary serialization, what's missing
From: Avi Bahra (avibahra_at_[hidden])
Date: 2009-11-26 03:52:37


Managed to recreate the binary serialization crash in 3 files

OS : Suse Linux
gcc : 4.2.1
Boost: 1.39

Files: RepeatAttr.hpp // only has an include for only the text
archive
            RepeatAttr.cpp
           TestSerialisation.cpp // include the main, and has
                                                   // includes for text and
binary archives

When the test is built there are no warnings on gcc, when the
test is run the text serialisation runs ok, but binary crashes
on serialising the base pointer.

To make the test pass uncomment out the binary archive
include in RepeatAttr.hpp and hey presto the test now passes.

//--------------------- RepeatAtrr.cpp --------------------

#include "RepeatAttr.hpp"
#include <sstream>
#include <boost/serialization/export.hpp>

using namespace std;

RepeatDate* RepeatDate::clone() const
{
    return new RepeatDate(name_, start_, end_, delta_) ;
}

bool RepeatDate::compare(RepeatBase* rb) const
{
    RepeatDate* rhs = dynamic_cast<RepeatDate*>(rb);
    if(!rhs) return false;
    return operator==(*rhs);
}

bool RepeatDate::operator==(const RepeatDate& rhs) const
{
    if (name_ != rhs.name_) return false;
    if (start_ != rhs.start_) return false;
    if (end_ != rhs.end_) return false;
    if (delta_ != rhs.delta_) return false;
    return true;
}
BOOST_SERIALIZATION_ASSUME_ABSTRACT(RepeatBase);
BOOST_CLASS_EXPORT(RepeatDate);

//--------------------- RepeatAtrr.hpp --------------------

#ifndef REPEATATTR_HPP_
#define REPEATATTR_HPP_

#include <ostream>

#include <boost/utility.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
//#include <boost/archive/binary_oarchive.hpp> // If this is
UNCOMMENTED NO CRASH
//#include <boost/archive/binary_iarchive.hpp> // If this is
UNCOMMENTED NO CRASH
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/assume_abstract.hpp>

class RepeatBase {
public:
    RepeatBase() {}
    virtual ~RepeatBase() {}

    virtual RepeatBase* clone() const = 0;
    virtual bool compare(RepeatBase*) const = 0;
    virtual std::string name() const = 0;

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

class RepeatDate : public RepeatBase {
public:
    RepeatDate(
           const std::string& variable,
           int start,
           int end,
           int delta /* always in days*/
           ) : name_(variable), start_(start), end_(end), delta_(delta),
value_(start) {}
    RepeatDate() : start_(0), end_(0), delta_(0), value_(0) {}

     bool operator==(const RepeatDate& rhs) const;

    virtual RepeatDate* clone() const ;
    virtual std::string name() const { return name_;}
    virtual bool compare(RepeatBase*) const;

private:
    std::string name_;
    int start_;
    int end_;
    int delta_;
    long value_;

    friend class boost::serialization::access;
    template<class Archive>
    void serialize(Archive & ar, const unsigned int /*version*/) {
        ar & boost::serialization::base_object<RepeatBase>(*this);
         ar & name_;
        ar & start_;
        ar & end_;
        ar & delta_;
        ar & value_;
    }
};

class Repeat {
public:

    Repeat() : repeatType_(NULL) {}
    Repeat( const RepeatDate& r) : repeatType_(new RepeatDate(r)) {}
    ~Repeat() { delete repeatType_;}

    std::string name() const { return
repeatType_->name();}
    bool operator==(const Repeat& rhs) const { return
repeatType_->compare(rhs.repeatType_); }

private:
    RepeatBase* repeatType_;

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

//--------------------- TestSerialisation.cpp --------------------

#include "RepeatAttr.hpp"

#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/utility.hpp>
#include <boost/serialization/vector.hpp> // no need to include <vector>
#include <boost/serialization/string.hpp> // no need to include <string>

#include <fstream>
#include <iostream>

#include <boost/serialization/export.hpp> // explicit code for exports
(place last)

class Suite {
public:
    Suite( const std::string& name ) : name_(name), repeat_(NULL) {}
    Suite() : repeat_(NULL) {}
    virtual ~Suite() {}

     const std::string& name() const { return name_; }

     bool operator==(const Suite& rhs) const { return name_ == rhs.name_;}

    bool addRepeat( const Repeat& r ) {
        if (repeat_) return false;
         repeat_ = new Repeat(r);
         return true;
    }

private:

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

    std::string name_;
    Repeat* repeat_;
};
BOOST_CLASS_EXPORT(Suite)

class Defs {
public:
    Defs( const std::string& name ) : fileName_(name) {}
    Defs() {}
    ~Defs() {}

     const std::string& fileName() const { return fileName_;}
    void fileName(const std::string& f) { fileName_ = f;}

    void addSuite(std::auto_ptr<Suite> s){
suiteVec_.push_back(s.release()); }

    bool operator==(const Defs& rhs) const {
        if ( fileName_ != rhs.fileName_ ) return false;
        if ( suiteVec_.size() != rhs.suiteVec_.size()) return false;
        for(unsigned i =0; i < suiteVec_.size(); ++i) {
            if ( !( *(suiteVec_[i]) == *(rhs.suiteVec_[i]) )) return false;
        }
         return true;
    }

    void save(bool binary) const
    {
        using namespace std;

        if (binary) {
            std::ofstream ofs( fileName_.c_str(), ios::binary );
            boost::archive::binary_oarchive oa( ofs );
            oa << *this;
        }
        else {
            std::ofstream ofs( fileName_.c_str() );
            boost::archive::text_oarchive oa( ofs );
             oa << *this;
        }

        if (binary) cout << "Saved binary " << fileName_ << "\n";
        else cout << "Saved text " << fileName_ << "\n";
     }

    void restore(bool binary)
    {
        using namespace std;
         if (!fileName_.empty()) {

            if (binary) {
                std::ifstream ifs( fileName_.c_str(), ios::binary);
                boost::archive::binary_iarchive ia(ifs);
                 ia >> (*this);
            }
            else {
                std::ifstream ifs( fileName_.c_str());
                boost::archive::text_iarchive ia(ifs);
                 ia >> (*this);
            }
            if (binary) cout << "Restored binary " << fileName_ << "\n";
            else cout << "Restored text " << fileName_ << "\n";
         }
    }

private:
    std::string fileName_;
    std::vector<Suite*> suiteVec_;

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

int main()
{
    {
        // ***** TEXT This works
        Defs saveDefs("saveFile.txt");
        std::auto_ptr<Suite> suite(new Suite("s3") );
        suite->addRepeat( RepeatDate("YMD",20090916,20090930,1));
        saveDefs.addSuite( suite );

        saveDefs.save(false);

        Defs loadDefs(saveDefs.fileName());
        loadDefs.restore(false);
        assert( saveDefs == loadDefs );
    }
    {
        // ****** BINARY This crashes
        // ****** Uncomment the binary include in RepeatAttr.hpp and it
works
        Defs saveDefs("saveFile.bin");
        std::auto_ptr<Suite> suite(new Suite("s3") );
        suite->addRepeat( RepeatDate("YMD",20090916,20090930,1));
        saveDefs.addSuite( suite );

        saveDefs.save(true);

        Defs loadDefs(saveDefs.fileName());
        loadDefs.restore(true);
        assert( saveDefs == loadDefs );
    }
    std::cout << "reached the end\n";
    return 0;
}
//-------------------------------------------------------------------------
  Best regards,
Ta,
   Avi



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