Reputation: 8422
I have a little problem with boost serialization. There are many examples that shows how to serialize a derived class pointer through the base class pointer by simply using BOOST_CLASS_EXPORT and BOOST_CLASS_EXPORT_IMPLEMENT. This is working fine and have no problems at all.
However, I do not want to serialize a pointer, as the deserialization in the other side should be again over a pointer and then, boost creates a new instance of the serialized object.
I can serialize a dereferenced pointer and then deserialize again over an existing object instance without problems, and no new instances are created. However, when the dereferenced pointer is over the base class, the derived class is not serialized as expected when serializing over pointers.
Working example:
Class A;
Class B : public A;
A* baseClass = new B();
ar << baseClass // works perfectly
Not working example:
Class A;
Class B : public A;
A* baseClass = new B();
ar << *baseClass; // only A is serialized
I can get it working by simple serializing over the derived class like:
B* derivedClass = new B();
ar << *derivedClass; // works fine
But all the references I have in my structures are of base class type. Also I cannot serialize the pointer as I do not need to instantiate new objetcs when deserializing, only "overwrite" the contents over an existing instance.
I have tried to serialize the pointer and trying to deserialize over an existing instance, but this does not work correctly. When I say deserialize over an existing instance, I mean:
A* baseClass = new B();
// baseClass is used in the program and in a given moment, its contents must be overwrite, so:
ar >> *baseClass;
As I said, I do not need a new instance of baseClass when deserializing. So, is there any way to get this working?
Upvotes: 2
Views: 2333
Reputation: 330
I think I understand the problem. When you do
ar >> *DerivedClass;
you are passing a reference to operator<<
. Now objects accessed through references to a base class are not properly serialized, as I gather from Robert Ramey's answer to this question in the Boost-users mailing list. Although the answer is several years old, I think it still holds true, because, if you think of it, the serialize
methods one writes are not virtual (they are templates, so they cannot be virtual).
So the library must be doing special stuff to handle pointers, but it is not doing it with references. An ugly solution I found is to add a pair of (virtual) serialize functions, like this:
virtual myser(iarchive &ia) {ia >> *this;}
virtual myser(oarchive &oa) {oa << *this;}
where iarchive
and oarchive
should be replaced with the archive you want. This sucks really, because apart from having to write two extra functions, you must explictly overload them for all the archive types you need. Unfortunately I do not know of a better solution.
Upvotes: 1
Reputation: 1216
I met the same problem with you! So I looked over the doc of boost,which give a way to solve the problem,I can define a class D to manage the derive objects,and use the ar.register_type
to diff the a b c class,just like this:
class base {
...
};
class derived_one : public base {
...
};
class derived_two : public base {
...
};
main(){
...
base *b;
...
ar & b;
}
When saving b what kind of object should be saved? When loading b what kind of object should be created? Should it be an object of class derived_one, derived_two, or maybe base?
It turns out that the kind of object serialized depends upon whether the base class (base in this case) is polymophic or not. If base is not polymorphic, that is if it has no virtual functions, then an object of the type base will be serialized. Information in any derived classes will be lost. If this is what is desired (it usually isn't) then no other effort is required.
If the base class is polymorphic, an object of the most derived type (derived_one or derived_two in this case) will be serialized. The question of which type of object is to be serialized is (almost) automatically handled by the library.
The system "registers" each class in an archive the first time an object of that class it is serialized and assigns a sequential number to it. Next time an object of that class is serialized in that same archive, this number is written in the archive. So every class is identified uniquely within the archive. When the archive is read back in, each new sequence number is re-associated with the class being read. Note that this implies that "registration" has to occur during both save and load so that the class-integer table built on load is identical to the class-integer table built on save. In fact, the key to whole serialization system is that things are always saved and loaded in the same sequence. This includes "registration".
main(){
derived_one d1;
derived_two d2:
...
ar & d1;
ar & d2;
// A side effect of serialization of objects d1 and d2 is that
// the classes derived_one and derived_two become known to the archive.
// So subsequent serialization of those classes by base pointer works
// without any special considerations.
base *b;
...
ar & b;
}
When b is read it is preceded by a unique (to the archive) class identifier which has previously been related to class derived_one or derived_two.
If a derived class has NOT been automatically "registered" as described above, an unregistered_class exception will be thrown when serialization is invoked.
This can be addressed by registering the derived class explicitly. All archives are derived from a base class which implements the following template:
template<class T>
register_type();
So our problem could just as well be addressed by writing:
main(){
...
ar.template register_type<derived_one>();
ar.template register_type<derived_two>();
base *b;
...
ar & b;
}
Note that if the serialization function is split between save and load, both functions must include the registration. This is required to keep the save and corresponding load in syncronization.
you can also use:
#include <boost/serialization/export.hpp>
...
BOOST_CLASS_EXPORT_GUID(derived_one, "derived_one")
BOOST_CLASS_EXPORT_GUID(derived_two, "derived_two")
main(){
...
base *b;
...
ar & b;
} The macro BOOST_CLASS_EXPORT_GUID associates a string literal with a class. In the above example we've used a string rendering of the class name. If a object of such an "exported" class is serialized through a pointer and is otherwise unregistered, the "export" string is included in the archive. When the archive is later read, the string literal is used to find the class which should be created by the serialization library. This permits each class to be in a separate header file along with its string identifier. There is no need to maintain a separate "pre-registration" of derived classes that might be serialized. This method of registration is referred to as "key export".
Maybe helpful for you!! for detail you can see this:http://www.boost.org/doc/libs/1_54_0/libs/serialization/doc/index.html
Upvotes: 2