boost serialization polymorphic issues - c++

Boost serialization of polymorphic classes seems not working ( 1.40+ boost), e.g. with the following code, I believe I followed the rule: of exporting the class and
I tried on both gcc4.4 (ubuntu) and windows VS2010(with boost 1.48):
in following program, I expect both 10 and 100 are printed, but it only print 10, that means it only serialized the base class;
I mostly copied the example from boost's document, yet it still doesn't work; anybody has any idea?
thanks a lot
LS
#include <iostream>
#include <sstream>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/export.hpp>
#define NVP(X) X
class base {
public:
friend class boost::serialization::access;
base (){ v1 = 10;}
int v1;
template<class Archive>
void serialize(Archive & ar, const unsigned int file_version)
{
ar & NVP(v1);
}
};
class derived : public base {
public:
friend class boost::serialization::access;
int v2 ;
derived() { v2 = 100;}
template<class Archive>
void serialize(Archive & ar, const unsigned int file_version){
boost::serialization::base_object<base>(* this);
ar & NVP(v2);
}
};
BOOST_CLASS_EXPORT(base);
BOOST_CLASS_EXPORT_GUID(derived, "derived");
int main ( )
{
std::stringstream ss;
boost::archive::text_oarchive ar(ss);
base *b = new derived();
ar << NVP(b);
std::cout << ss.str();
}

You forgot
virtual ~base() {}
which is not only required for the polymorphic seriialization to work (without it your class is not polymorphic), but I believe omitting it is a misdemeanor in 48 states. IANAL, so YMMV.
Oh, and it should be ar & boost::serialization::base_object<...>.

Related

Serializing Vector of Objects which contains Vectors of Pointers

I have 3 classes ("Leader", "Researchers", "Workers") which all derive from a base-class "Team".
I have a class "Project" which contains a vector of pointers to different Teams.
I use all of the following headers, in this order, in all of my class declarations:
#include <sstream>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/version.hpp>
#include <boost/serialization/split_member.hpp>
To (de)serialize the Team object I use:
private:
friend class boost::serialization::access ;
template <typename Archive>
void serialize(Archive& ar, const unsigned int /*version*/)
{
ar & teamname ;
}
To (de)serialize the Leader, Researchers, Workers objects I use:
typedef Team _super;
friend class boost::serialization::access ;
template <typename Archive>
void serialize(Archive& ar, const unsigned int /*version*/)
{
ar & boost::serialization::base_object<_super>(*this) ;
ar & contactTelephoneNumber ;
}
The Project holds a std::vector of pointers to different teams and a string using:
std::vector<Team *> teams ;
std::string note ;
I use the following code in the Project class for serialization:
private:
friend class boost::serialization::access ;
template <typename Archive>
void serialize(Archive& ar, const unsigned int /*version*/)
{
//ar & BOOST_SERIALIZATION_NVP(teams) ; //ERROR OCCURS HERE
ar & teams;
ar & note ;
}
And to serialize the vector of Project objects in the main I use:
{
std::ostringstream archiveStream ;
boost::archive::text_oarchive archive(archiveStream) ;
archive << BOOST_SERIALIZATION_NVP(projects) ;
//Get serialized info as string
archivedProjects = archiveStream.str() ;
}
This all compiles fine. The issue is at Run-Time. When the above section of the code is reached, I get the following error:
terminate called after throwing an instance of 'boost::archive::archive_exception'
what():
unregistered class - derevided class not registered or exported"
The program goes as far as:
ar & teams;
In the Questionnaire class's serialization attempt.
As in n.m.'s link: you need to register the classes with Boost so that it knows what classes are what when serialising.
You need to add the following line for each class where "Project" serializes:
ar.template register_type<ClassName>() ; //ClassName = Team etc

Serialization of derived class trips Boost assertion

When trying to serialize a derived class with boost::serialization, an assertion in boost/archive/detail/oserializer.hpp (line 436 in Boost 1.53.0) is tripped:
const basic_pointer_oserializer * bpos
= static_cast<const basic_pointer_oserializer *>(
boost::serialization::singleton<
archive_serializer_map<Archive>
>::get_const_instance().find(*true_type)
);
BOOST_ASSERT(NULL != bpos);
Here is my MWE:
#include <iostream>
#include <fstream>
#include <boost/archive/polymorphic_xml_oarchive.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/access.hpp>
#include <boost/serialization/base_object.hpp>
class base
{
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive &ar, const unsigned int version)
{
ar & boost::serialization::make_nvp("test", test);
}
int test;
public:
virtual void print() { std::cout << 1 << std::endl; }
};
class derived : public base
{
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive &ar, const unsigned int version)
{
ar & boost::serialization::make_nvp("base", boost::serialization::base_object<base>(*this));
ar & boost::serialization::make_nvp("test2", test2);
}
int test2;
public:
void print() { std::cout << 2 << std::endl; }
};
int main (int argc, char const *argv[])
{
base *b = new derived();
std::ofstream stream("out.xml");
boost::archive::polymorphic_xml_oarchive ar(stream);
ar.register_type<derived>();
ar << boost::serialization::make_nvp("b", b);
return 0;
}
I also tried using BOOST_CLASS_EXPORT_GUID instead of register_type, but that also didn't work. Any idea what I'm doing wrong?
You probably don't mean to use polymorphic_xml_archive (see docs).
Notably, polymorphic archives have to do with the interface of the archives, nothing with the entities you're serializing for (they can always be polymorphic).
If you use xml_archive instead, the problem vanishes.

correct type-cast for boost de-serializations of different derived classes

In my application, there are agents of different types. I am planning to use boost serialization for sending/receiving data between agents.(by sending/receiving, I actually mean writing/reading operation the serialization target file)
A receiving agent may receive data of different data whose type is not known in advance. Suppose the data format has a general structure like this:
class Base
{
public:
int message_type_id;
}
class Derived_1
{
public:
Derived_1(int message_type_id_):message_type_id(message_type_id_){}
struct data_1 {...};
};
class Derived_2
{
public:
Derived_2(int message_type_id_):message_type_id(message_type_id_){}
struct data_2 {...};
};
the sending agent can send(i.e serialize) any of the two derived types. Similarly, the receiving agent can receive(i.e de-serialize) any of the two derived types; while what I can see in the tutorial(Dumping derived classes through base class pointers) is like this:
void save()
{
std::ofstream file("archive.xml"); //target file
boost::archive::xml_oarchive oa(file);
oa.register_type<date>( );// you know what you are sending, so you make proper modifications here to do proper registration
base* b = new date(15, 8, 1947);
oa & BOOST_SERIALIZATION_NVP(b);
}
void load()
{
std::ifstream file("archive.xml"); //target file
boost::archive::xml_iarchive ia(file);
ia.register_type<date>( );// I don't know which derived class I am receiving, so I can't do a proper registration
base *dr;
ia >> BOOST_SERIALIZATION_NVP(dr);
date* dr2 = dynamic_cast<date*> (dr);
std::cout << dr2;
}
as you can see, xml_oarchive and xml_iarchive do a register_type<date> before serialize/deserialization. so the receiving end will know in advance what to dynamic_cast to.
whereas in my case, since I know what I am sending, I can do proper registration&serialization on case-to-case basis. However, on the receiving end, I dont't know in advance what to register and what to dynamic cast.
Is there a way I can tell the type in advance so that the receiving can do a casting?
thanks
EDIT:
Here is the simplified modification of demo.cpp I save an object, and then restore it.
#include <cstddef> // NULL
#include <iomanip>
#include <iostream>
#include <fstream>
#include <string>
#include <boost/archive/tmpdir.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/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>
/*
bus_stop is the base class.
bus_stop_corner and bus_stop_destination are derived classes from the above base class.
bus_route has a container that stores pointer to the above derived classes
*/
class bus_stop
{
friend class boost::serialization::access;
virtual std::string description() const = 0;
template<class Archive>
void serialize(Archive &ar, const unsigned int version)
{
ar & type;
}
protected:
public:
std::string type;
bus_stop(){type = "Base";}
virtual ~bus_stop(){}
};
BOOST_SERIALIZATION_ASSUME_ABSTRACT(bus_stop)
class bus_stop_corner : public bus_stop
{
friend class boost::serialization::access;
virtual std::string description() const
{
return street1 + " and " + street2;
}
template<class Archive>
void serialize(Archive &ar, const unsigned int version)
{
// save/load base class information
ar & boost::serialization::base_object<bus_stop>(*this);
ar & street1 & street2;
}
public:
std::string street1;
std::string street2;
bus_stop_corner(){}
bus_stop_corner(
const std::string & _s1, const std::string & _s2
) :
street1(_s1), street2(_s2)
{
type = "derived_bs_corner";
}
};
class bus_stop_destination : public bus_stop
{
friend class boost::serialization::access;
virtual std::string description() const
{
return name;
}
template<class Archive>
void serialize(Archive &ar, const unsigned int version)
{
ar & boost::serialization::base_object<bus_stop>(*this) & name;
}
public:
std::string name;
bus_stop_destination(){}
bus_stop_destination(
const std::string & _name
) :
name(_name)
{
type = "derived_bs_destination";
}
};
class bus_route
{
friend class boost::serialization::access;
typedef bus_stop * bus_stop_pointer;
template<class Archive>
void serialize(Archive &ar, const unsigned int version)
{
ar.register_type(static_cast<bus_stop_corner *>(NULL));
ar.register_type(static_cast<bus_stop_destination *>(NULL));
ar & stops;
}
public:
std::list<bus_stop_pointer> stops;
bus_route(){}
void append(bus_stop *_bs)
{
stops.insert(stops.end(), _bs);
}
};
//BOOST_CLASS_VERSION(bus_route, 2)
void save_schedule(const bus_route s, const char * filename){
// make an archive
std::ofstream ofs(filename);
boost::archive::text_oarchive oa(ofs);
oa << s;
}
void
restore_schedule(bus_route &s, const char * filename)
{
// open the archive
std::ifstream ifs(filename);
boost::archive::text_iarchive ia(ifs);
// restore the schedule from the archive
ia >> s;
}
int main(int argc, char *argv[])
{
bus_stop *bs1 = new bus_stop_corner(
"First St", "Second st"
);
bus_stop *bs2 = new bus_stop_destination(
"myName"
);
// make a routes
bus_route original_route;
original_route.append(bs1);
original_route.append(bs2);
std::string filename1(boost::archive::tmpdir());
filename1 += "/demofile1.txt";
save_schedule(original_route, filename1.c_str());
bus_route new_route ;
restore_schedule(new_route, filename1.c_str());
////////////////////////////////////////////////////////
std::string filename2(boost::archive::tmpdir());
filename2 += "/demofile2.txt";
save_schedule(new_route, filename2.c_str());
delete bs1;
delete bs2;
return 0;
}
The old and new objects are not equal coz again saving(serializing) the new object to another file results in a different(empty) content. Can you please let me know how I can fix this code to deserialize the derived classes successfully? many thanks
EDIT-2
There is nothing wrong with the above code now(after a small typo was fixed).
I am answering my own question here coz there is another good approach suggested by someone else.
So the Answer to my first question is like this :
As long as you register the derived types in the main serialization function (in the above case: serialize() in bus_route class) everything should be fine.
thanks for all the help
A solution is to (de-)serialize boost::shared_ptr<Base>. The following code demonstrates it. After deserialization the pDst is an instance of the Derived_1 class. The code complied using an online compiler is available on this link.
#include <boost/serialization/access.hpp>
#include <boost/serialization/assume_abstract.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/noncopyable.hpp>
#include <boost/make_shared.hpp>
#include <boost/smart_ptr/shared_ptr.hpp>
class Base {
friend class boost::serialization::access;
public:
Base();
virtual ~Base();
private:
template<class Archive> void serialize(Archive &ar, const unsigned int version) {}
public:
virtual bool operator ==(const Base &rh) const = 0;
};
BOOST_SERIALIZATION_ASSUME_ABSTRACT(Base)
BOOST_SERIALIZATION_SHARED_PTR(Base)
Base::Base() {
}
Base::~Base() {
}
class Derived_1 : boost::noncopyable, public Base {
friend class boost::serialization::access;
public:
int m_iValue;
public:
Derived_1();
Derived_1(int iValue);
private:
template<class Archive> void serialize(Archive &ar, const unsigned int version) {
ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base);
ar & boost::serialization::make_nvp("value", m_iValue);
}
public:
bool operator ==(const Base &rh) const;
};
BOOST_SERIALIZATION_SHARED_PTR(Derived_1)
Derived_1::Derived_1() : m_iValue(0) {
}
Derived_1::Derived_1(int iValue) : m_iValue(iValue) {
}
bool Derived_1::operator==(const Base &rh) const {
const Derived_1 *pRH = dynamic_cast<const Derived_1 *>(&rh);
return pRH != nullptr && pRH->m_iValue == this->m_iValue;
}
#include <boost/serialization/export.hpp>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/make_shared.hpp>
#include <sstream>
#include <string>
BOOST_CLASS_EXPORT_GUID(Base, "base")
BOOST_CLASS_EXPORT_GUID(Derived_1, "derived_1")
void test(void) {
std::string str;
boost::shared_ptr<Base> pSrc = boost::make_shared<Derived_1>(10);
boost::shared_ptr<Base> pDst;
{
std::ostringstream ofs;
boost::archive::xml_oarchive oa(ofs);
oa << boost::serialization::make_nvp("item", pSrc);
str = ofs.str();
}
{
std::istringstream ifs(str);
boost::archive::xml_iarchive ia(ifs);
ia >> boost::serialization::make_nvp("item", pDst);
}
if (*pSrc == *pDst) {
printf("Success\n");
}
else {
printf("Fail\n");
}
}
int main(int argc, char* argv[]) {
test();
}

Boost deserialize a derived class to base class pointer

Please help me deserialize a derived class to base-class pointer. I attach the complete source code example.
request.hpp (no pair cpp file)
#ifndef REQUEST_HPP
#define REQUEST_HPP
#include <memory>
#include <string>
#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/xml_iarchive.hpp>
namespace demo {
namespace common {
class request {
public:
static const int INVALID_ID = -42;
request()
: id_(INVALID_ID), timestamp_(0), source_ip_("unknown") {};
request(int id, long timestamp, const std::string& source_ip)
: id_(id), timestamp_(timestamp), source_ip_(source_ip) {};
virtual ~request() {};
int id() const { return id_; }
long timestamp() const { return timestamp_; }
std::string source_ip() const { return source_ip_; }
protected:
int id_;
long timestamp_;
std::string source_ip_;
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive& ar, const unsigned version) {
ar & BOOST_SERIALIZATION_NVP(id_);
ar & BOOST_SERIALIZATION_NVP(timestamp_);
ar & BOOST_SERIALIZATION_NVP(source_ip_);
}
};
typedef std::shared_ptr<request> request_ptr;
}
};
#endif
command.hpp (derived class)
#ifndef COMMAND_HPP
#define COMMAND_HPP
#include <memory>
#include <string>
#include <boost/serialization/export.hpp>
#include <demo/common/request.hpp>
namespace demo {
namespace common {
class command : public request {
public:
command(): name_("untitled") {};
explicit command(const std::string& name) : name_(name) {};
virtual ~command() {};
virtual void execute();
std::string name() const { return name_; }
protected:
std::string name_;
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive& ar, const unsigned version) {
ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(request);
ar & BOOST_SERIALIZATION_NVP(name_);
}
};
typedef std::shared_ptr<command> command_ptr;
}
};
BOOST_CLASS_EXPORT_KEY(demo::common::command)
#endif
command.cpp
#include "command.hpp"
#include <iostream>
BOOST_CLASS_EXPORT_IMPLEMENT(demo::common::command)
namespace demo {
namespace common {
void command::execute() {
std::cout << " I am '" + name_ +"' and I am executing..." << std::endl;
}
}
};
serializer.hpp
#ifndef SERIALIZER_HPP
#define SERIALIZER_HPP
#include <sstream>
#include <string>
/* classes to serialize */
#include <demo/common/request.hpp>
#include <demo/common/command.hpp>
namespace demo {
namespace common {
class serializer {
public:
serializer() : {};
template<typename T>
std::string serialize(const T& t){
std::stringstream stream;
boost::archive::xml_oarchive archive(stream);
archive << BOOST_SERIALIZATION_NVP(t);
std::string serialized = stream.str();
return serialized;
}
template<typename T>
void deserialize(const std::string& serialized, T& t) {
std::stringstream stream(serialized);
boost::archive::xml_iarchive archive(stream);
archive >> BOOST_SERIALIZATION_NVP(t);
}
};
}
}
#endif
sample usage
#include <iostream>
#include <demo/common/serializer.hpp>
#include <demo/common/command.hpp>
using namespace std;
using namespace demo::common;
int main(){
serializer serializer_;
command r("123"); // <-- (1) my desired way of declaring
//request* r = new command("123"); <-- (2) replacing with this makes all work!
//command* r = new command("123"); <-- (3) replacing with this crashes the app, like (1)
std::string s = serializer_.serialize(r);
std::cout << s << std::endl;
request* rr = nullptr;
serializer_.deserialize(s, rr); //this throws an exception
command* rrr = dynamic_cast<command*>(rr);
rrr->execute();
}
I thought I did everything that needs to be done, archives included before any class export, all default constructors initialize members..
Note that the serializable classes and the serializer are compiled to a lib file. Then that lib is used in two sub-projects that have access to the headers and have that lib linked. They use those classes to communicate with each other, they send serialized objects over network.
Why can't I deserialize a derived class to a base class pointer?
I am using Boost 1.51 and VC11.
Problems:
The two major things I found finicky and not documented enough about Boost::serialization that caused me issues are as follows:
Serialization / deserialization of objects on the stack mixed with objects on the heap. For example if you serialize from a object on the stack then attempt to deserialize to a pointer (e.g. invoke your load_construct_data<>) an exception may occur. Same with the reverse scenario.
Not having your exports linked in properly. If you create serialization templates/classes and place them in a .lib for example, it seems the exports may not be properly linked in / exposed. This goes for linking in and then using from a shared object/DLL.
Solutions:
For #1, I've found it easiest to make a rule of always serializing/deserializing to/from pointers. Even objects on the stack can use a temporary pointer when serializing to allow for this rule. For example:
// serialize
MyObject myobj;
std::ostringstream oss;
boost::archive::text_oarchive oa(oss);
MyObject* myObjPtr = &myObj;
oa << myObjPtr; // this is different than oa << myObj!!
std::string serialized = oss.str();
// deserialize
MyObject* myNewObjPtr;
std::stringstream iss(serialized);
boost::archive::text_iarchive ia(iss);
ia >> myNewObjPtr; // invokes new, don't forget to delete (or use smart ptrs!!!)
For #2, simply create a .cpp file that contains all of your exports. Link this CPP into your module(s) directly. In other words, you'll have a .cpp with a bunch of BOOST_CLASS_EXPORT_IMPLEMENT():
BOOST_CLASS_EXPORT_IMPLEMENT(MyObject);
// ...
More Complete Example:
Below is a more complete example showing some of the serialization tricks using non-intrusive templates. Intrusive member methods will be very similar:
MyObject.h
// Can be broken into MyObject.h, MyObject.cpp, MyObjectSerialization.h for example as well.
// This stuff can live in your .lib
#include <boost/serialization/export.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
// assume this class contains GetSomeMember() returning SomeMemberType
class MyObject { /* ... */ };
BOOST_CLASS_EXPORT_KEY(MyObject);
namespace boost { namespace serialization {
template<class Archive>
void serialize(Archive& ar, MyObject& myObj, const unsigned int version)
{
ar & myObj.m_someMember;
}
template<class Archive>
inline void save_construct_data(Archive& ar, const MyObject* myObj, const unsigned int version)
{
ar & boost::serialization::make_nvp("SomeMemberType", static_cast<const SomeMemberType&>(myObj->GetSomeMember()));
}
template<class Archive>
inline void load_construct_data(Archive& ar, MyObject* myObj, const unsigned int version)
{
SomeMemberType t;
ar & boost::serialization::make_nvp("SomeMemberType", t);
::new(myObj)MyObject(t);
}
} } // end boost::serialization ns
MyObjectExports.cpp
// This file must be explicitly linked into your module(s) that use serialization.
// This means your executable or shared module/DLLs
#include <boost/serialization/export.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include "MyObject.h"
BOOST_CLASS_EXPORT_IMPLEMENT(MyObject);
You're probably getting an input_stream_error in your demo and unregistered_class exception when using your library. This is caused by the way boost is registering the classes, in your case, automatically.
It appears that the automatic registration process gets confused when you serialize a derived object and deserialize to its base, despite the use of the BOOST_CLASS_EXPORT* macros.
However, you can register the classes explicitly before you perform any i/o operation on the archive:
// ...
boost::archive::xml_iarchive archive(stream);
// register the class(es) with the archive
archive.template register_type<command>();
archive >> BOOST_SERIALIZATION_NVP(t);
// ...
Use the same order of registration when serializing. This makes the export macros superfluous.

Serializing a map of objects to xml using boost::serialization

The serialization example below is from the boost mailing list which is pretty much the same as what I would like to do. However, I have changed the archive so that it will serialize to XML. The compile does not fail if I serialize to binary, but it fails when serializing to xml. The compile fails in basic_xml_oarchive.hpp in the following method:
// boost code where compile fails
template<class T>
void save_override(T & t, BOOST_PFTO int)
{
// If your program fails to compile here, its most likely due to
// not specifying an nvp wrapper around the variable to
// be serialized.
BOOST_MPL_ASSERT((serialization::is_wrapper<T>));
this->detail_common_oarchive::save_override(t, 0);
}
It seems I haven't done enough to allow the std::map<int, CSomeData> object to be serialized, any ideas on how to fix this?
My serialization implementation:
#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/serialization/map.hpp>
#include <fstream>
#include <string>
#include <map>
using namespace std;
// This is a test class to use as the map data.
class CSomeData {
public:
CSomeData(){};
CSomeData(float f0, string str0)
{
m_f0 = f0;
m_str0 = str0;
}
float m_f0;
string m_str0;
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive &ar, const unsigned int version)
{
ar & m_f0;
ar & m_str0;
}
};
// This is the class we really want to try serializing.
class CTest {
public:
CTest(){};
CTest(int nNumber)
{
m_nNumber = nNumber;
// Fill with some dummy data.
m_mTst.insert(make_pair(0, CSomeData(0.23f, "hi hi hi")));
m_mTst.insert(make_pair(1, CSomeData(7.65f, "second one")));
m_mTst.insert(make_pair(2, CSomeData(9.23f, "third one")));
m_mTst.insert(make_pair(3, CSomeData(5.6766, "chosen one")));
}
~CTest(){};
save()
{
std::ofstream ofs("filename");
// Write class instance to archive. Writing seems to work ok.
boost::archive::xml_oarchive oa(ofs);
oa << BOOST_SERIALIZATION_NVP(*this);
}
int m_nNumber;
private:
map<int, CSomeData> m_mTst;
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive &ar, const unsigned int version)
{
ar & m_nNumber;
ar & m_mTst;
}
};
I believe you need to tag the members with a name for XML serialisation. This specifies the element name to use in the XML. I.e. use something like:
ar & BOOST_SERIALIZATION_NVP(m_f0);
or (better in this case):
ar & make_nvp("field0", my_f0);
The tags will be ignored for binary serialisation. More details here:
http://www.boost.org/doc/libs/1_43_0/libs/serialization/doc/wrappers.html