boost serialization and polymorphic collection

Started by
3 comments, last by _moagstar_ 14 years, 8 months ago
I tried to construct a minimal program with a vector polymorphically storing a number of objects of different classes, and then use boost serialization to serialize/deserialize it. The problem is, the program below crashes when I don't comment out the two lines marked with "//causes exception". I'm not surprised, because as far as I know there's no way for the serialization framework to properly construct the necessary objects with the right type, because in C++ there's simply no generic way of constructing an object given typeinfo, an id or similar, unless I create my own factory class for this. So, how should scenarios such as the one below be handled in practice? E.g. I have a polymorphic collection of classes allocated on the heap and would like to serialize/deserialize it.

#include <fstream>
#include <vector>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/base_object.hpp>

class Foo {
public:
	Foo(int x) : x(x) {}
	virtual void foo() const { std::cout << "Foo! " << x << "\n"; }

protected:
	int x;
	Foo() {}

private:
	friend class boost::serialization::access;

	template<class Archive>
	void serialize(Archive & ar, const unsigned int version) {
		ar & x;
	}
};
class Bar1 : public Foo {
public:
	Bar1(int x) : Foo(x), bar("Hello!") {}
	virtual void foo() const { std::cout << "Bar1! " << x << " " << bar << "\n"; }

private:
	friend class boost::serialization::access;
	Bar1() {}

	template<class Archive>
	void serialize(Archive & ar, const unsigned int version) {
		ar & boost::serialization::base_object<Foo>(*this);
		ar & bar;
	}

	std::string bar;
};
class Bar2 : public Foo {
public:
	Bar2(int x) : Foo(x), bar(3.14159265) {}
	virtual void foo() const { std::cout << "Bar2! " << x << "\n"; }

private:
	friend class boost::serialization::access;
	Bar2() {}
	template<class Archive>
	void serialize(Archive & ar, const unsigned int version) {
		ar & boost::serialization::base_object<Foo>(*this);
		ar & bar;
	}
	double bar;
};

void printPtrVec(const std::vector<Foo *>& hello) {
	for(std::vector<Foo *>::const_iterator it = hello.begin(); it != hello.end(); ++it) {
		(*it)->foo();
	}
}

int main(int argc, char *argv[]) {
	std::vector<Foo *> hello;
	hello.push_back(new Foo(1));
	hello.push_back(new Bar1(2)); //causes exception
	hello.push_back(new Bar2(3)); //causes exception

	std::ofstream ofs("tmp.txt");
	boost::archive::text_oarchive oa(ofs);
	oa << hello;
	ofs.close();

	printPtrVec(hello);

	std::cout << "Serialized!\n";

	hello.clear();

	std::ifstream ifs("tmp.txt");
	boost::archive::text_iarchive ia(ifs);
	ia >> hello;
	ifs.close();

	std::cout << "Deserialized!\n";

	printPtrVec(hello);

	std::cout << "Successful!\n";
	std::cin.get();

	return 0;
}


Edit: sexier indentation [Edited by - all_names_taken on August 15, 2009 3:51:47 AM]
Advertisement
Where does it crash? I have no experience with boost so I'm possibly not in the position to actually help you but does it crash when you push the value, or does it crash later in the program when you have already pushed the value's (now I reread the sentence its really badly formulated:P).
if (*pYou == ASSHOLE) { pYou->Die(); delete pYou; };
You need to export those derived classes :

#include <boost/serialization/export.hpp>//...BOOST_CLASS_EXPORT(Bar1);BOOST_CLASS_EXPORT(Bar2);//...


This should provide the serialization library with the necessary information to create the correct objects.
Great, now it works! I'll have to take a look out how they implemented such an awesome thing!

One more thing I forgot to ask, why do I get this warning when compiling the above program (and the fixed program) with MSVC?
* boost/archive/detail/oserializer.hpp(538) : warning C4099: 'boost::serialization::static_warning_impl<false>::STATIC_WARNING' : type name first seen using 'struct' now seen using 'class'* boost/serialization/static_warning.hpp(115) : see declaration of 'boost::serialization::static_warning_impl<false>::STATIC_WARNING'* boost/archive/detail/common_oarchive.hpp(64) : see reference to function template instantiation 'void boost::archive::save<Archive,T>(Archive &,T &)' being compiled        with        [            Archive=boost::archive::text_oarchive,            T=std::vector<Foo *>        ]* boost/archive/basic_text_oarchive.hpp(75) : see reference to function template instantiation 'void boost::archive::detail::common_oarchive<Archive>::save_override<T>(T &,int)' being compiled        with        [            Archive=boost::archive::text_oarchive,            T=std::vector<Foo *>        ]* boost/archive/detail/interface_oarchive.hpp(64) : see reference to function template instantiation 'void boost::archive::basic_text_oarchive<Archive>::save_override<T>(T &,int)' being compiled        with        [            Archive=boost::archive::text_oarchive,            T=std::vector<Foo *>        ]        .\main.cpp(107) : see reference to function template instantiation 'Archive &boost::archive::detail::interface_oarchive<Archive>::operator <<<std::vector<_Ty>>(T &)' being compiled        with        [            Archive=boost::archive::text_oarchive,            _Ty=Foo *,            T=std::vector<Foo *>        ]
This is a warning generated by boost.serialisation in two circumstances, when you are serialising an object with tracking set to boost::serialization::track_never or when you are serialising a non-const object which isn't marked as boost::serialization::track_never, it is designed to trap possible errors with using the library. Here is a rationale behind it.

You are doing the latter. If you const_cast your object before serialising it you can remove the warning :

oa << const_cast<const std::vector<Foo *>&>(hello);


You can read more about object tracking (including the default tracking levels) here.

Good luck!

This topic is closed to new replies.

Advertisement