O
okinrus
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->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;
}
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->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;
}