Serializing non-default-constructible objects with boost

By Lev

Boost serialization is not trivial for an object that has no default constructor. Consider this:

class Foo
{
public:
	int v1;
	int v2;

	Foo(int v1_) { v1 = v1_; }

	template <typename Archive>
	void serialize(Archive& ar, unsigned int version)
	{
		ar & v1;
		ar & v2;
	}
};

//...
binary_iarchive ar;
Foo foo(0);
ar >> foo;

We only suffer a minor inelegance because of redundantly initializing foo. But what if we need to deserialize a pointer?

shared_ptr<Foo> fooPtr;
binary_iarchive ar;
ar >> fooPtr;

This won’t compile, because the deserialization of fooPtr will more or less amount to this:

fooPtr.reset(new Foo);
ar >> *fooPtr;

But of course the first line can’t compile.

Boost’s own doc proposes a solution by overriding two internal functions. One will write v1 (m_attribute in their example), the other will read it and pass to the constructor. Note that v1 is serialized outside serialize().

The solution uses a little-known syntax: ::new(t) my_class(attribute);. This is an explicit constructor call without allocation, which intuitively would be written as t->my_class(attribute);. It is interesting to note that the latter syntax is allowed for destructors: t->~my_class();

My answer to the problem is more like the first example, where the object is dummy-initialized:

namespace boost
{
	namespace serialization
	{
		template<class Archive>
		void load_construct_data(Archive & /*ar*/,
			Foo* t, const unsigned int /*file_version*/)
		{
			::new(t) Foo(0);
		}
	}
}

This simply explains Boost that the correct way of initializing a new Foo is to pass it zero.

Tags: ,

Leave a Reply