Problem with serialization

From: okinrus (okinrus_at_yahoo.com)
Date: 06/30/04


Date: 29 Jun 2004 21:25:59 -0700

Can someone take a look at this code and figure out why
Serializable_base::add_serializer throws std::bad_alloc. The problem
seems to be the compiler because msvc++ 7.1 says
c:\LibSerial\LibSerial.cpp(83) : warning C4584: 'serial::E' :
base-class 'serial::A' is already a base-class of 'serial::C'
        c:\LibSerial\LibSerial.cpp(10) : see declaration of
'serial::A'
        c:\LibSerial\LibSerial.cpp(48) : see declaration of
'serial::C'

#include <vector>
#include <iostream>

//#include "Archive.h"
//
// Archive is an abstract class that defines write(int), write(float)
etc.
// But for our purposes it can be just defined to be
//
namespace serial {

class Archive { };

template<class T>
inline Archive& operator&=(Archive& ar, T& x)
{
     return ar;
}

}

namespace serial {

class Serializable_base;
class Serial_holder;

// Serialize_base will store a vector of
// Serialize_action_base objects which
// will then be called back in predefined order
// at serialization
class Serialize_action_base
{
public:
    virtual void serialize(Archive& ar) = 0;
};

// This should call the serialize method of a class T
template<typename T>
class Serialize_action : public Serialize_action_base
{
    T* sc;
public:
    Serialize_action() : sc(0)
    { }

    void set_obj(T* serial)
    {
        sc = serial;
    }

    void serialize(Archive& ar)
    {
        if (sc != 0)
        {
            sc->T::serialize(ar);
        }
    }
};
 

// Serializable virtually inherits from this class to retrieve
// a unique id
class Serializable_base
{
    friend class Serial_holder;
public:
    Serializable_base()
    {
        std::cout << "Serializable_base()" << std::endl;
    }

    virtual ~Serializable_base()
    {
        std::cout << "Serializable_base destroyed" << std::endl;
    }
protected:
    // this is where std::bad_alloc is thrown
    void add_serializer(Serialize_action_base* serializer)
    {
        serializers.push_back(serializer);
    }
private:
    typedef std::vector<Serialize_action_base*> serializer_actions;
    serializer_actions serializers;
    

    void serialize_all(Archive& ar)
    {
        std::cout << "num serializers = " << serializers.size() <<
std::endl;
        for (size_t i = 0; i < serializers.size(); ++i)
            serializers[i]->serialize(ar);
    }
};

// T is the class that inherits from this class
template<typename T>
class Serializable : public virtual Serializable_base
{
    typedef T Base;

    friend class Serialize_action;

    // This serialize method function should be invoked within the
    // Serialize_action object. It should just call the class
    // who derives from this class serialize method, which
    // means that any class that we should be able to make a
    // given class Serializable by writing
    //
    // class C : public Serializable<C>
    // {
    // void serialize(Archive& ar) { }
    // };
    void serialize(Archive& ar)
    {
        Base* base = dynamic_cast<Base*>(this);
        if (base)
            base->serialize(ar);
    }
public:
    Serializable()
        : Serializable_base()
    {
        std::cout << "Serializable()" << std::endl;
        sa.set_obj(this);
        add_serializer(&sa);
    }
private:
    Serialize_action<Serializable<T> > sa;
};

class Serial_holder
{
public:
    Serial_holder(Serializable_base* r)
        : root(r)
    { }

 
    void serialize(Archive& ar)
    {
        root->serialize_all(ar);
    }
private:
    Serializable_base* root;
};

}

#endif

//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////

// Do some tests of the serialize classes
#include "LibSerial.h"
#include <iostream>
using namespace serial;

class A : public Serializable<A>
{
    int a;
    int b;
    int c;
public:
    A() : a(1), b(2), c(3) { }

    ~A()
    {
        std::cout << "A destroyed" << std::endl;
    }

    void serialize(Archive& ar)
    {
        std::cout << "Serializing A" << std::endl;
        ar &= a;
        ar &= b;
        ar &= c;
    }
};

class B : public Serializable<B>
{
    int a;
    int b;
public:
    B() : a(4), b(5) { }

    void serialize(Archive& ar)
    {
        std::cout << "Serializing B" << std::endl;
        ar &= a;
        ar &= b;
    }

};

class C : public A, public B, public Serializable<C>
{
    int c;
    int d;
public:
    C() : c(6), d(7) { }

    void serialize(Archive& ar)
    {
        std::cout << "Serializing C" << std::endl;
        ar &= c;
        ar &= d;
    }
};

class D : public B, public A, public Serializable<D>
{
    int e;
    int f;
    int g;
public:
    D() : e(4), f(5), g(6)
    {

    }

    void serialize(Archive& ar)
    {
        std::cout << "Serializing D" << std::endl;
        ar &= e;
        ar &= f;
        ar &= g;
    }
};

class E : public A, public C, public Serializable<E>
{
    int e;
public:
    E() : e(5) { }

    void serialize(Archive& ar)
    {
        std::cout << "Serializing E" << std::endl;
        ar &= e;
    }
};

/// T is the class that were're testing
template<class T>
void do_test(serial::Archive& ar)
{
    T c;

    std::cout << "testing " << typeid(c).name() << std::endl;

    Serial_holder sh(&c);
    sh.serialize(ar);
}

int main()
{
    serial::Archive ar;
    do_test<E>(ar);

    return 0;
}


Loading