[serialization] cyclic references

I have difficulties when serializing two objects pointing to each other. The generated archive is fine (I can see both references in it), but when deserializing, only one is restored. In the attached example, I have a collection of nodes, each one is pointing to the previous and to the next node. When deserializing, only the ->next references are restored, all the ->previous are NULL. The compiler is VC7.1 Thanks, Francois Fath -- Disclaimer ------------------------------------ Ce message ainsi que les eventuelles pieces jointes constituent une correspondance privee et confidentielle a l'attention exclusive du destinataire designe ci-dessus. Si vous n'etes pas le destinataire du present message ou une personne susceptible de pouvoir le lui delivrer, il vous est signifie que toute divulgation, distribution ou copie de cette transmission est strictement interdite. Si vous avez recu ce message par erreur, nous vous remercions d'en informer l'expediteur par telephone ou de lui retourner le present message, puis d'effacer immediatement ce message de votre systeme. *** This e-mail and any attachments is a confidential correspondence intended only for use of the individual or entity named above. If you are not the intended recipient or the agent responsible for delivering the message to the intended recipient, you are hereby notified that any disclosure, distribution or copying of this communication is strictly prohibited. If you have received this communication in error, please notify the sender by phone or by replying this message, and then delete this message from your system. #include "stdafx.h" #include <fstream> #include <boost/archive/xml_oarchive.hpp> #include <boost/archive/xml_iarchive.hpp> using namespace std; class Node { public: Node(Node *previous = NULL, Node *next = NULL) { id = ++count; this->previous = previous; if (previous) previous->next = this; this->next = next; if (next) next->previous = this; } ~Node() { if (previous) previous->next = next; if (next) next->previous = previous; } private: static unsigned int count; unsigned int id; Node *previous; Node *next; friend class boost::serialization::access; template<class Archive> void serialize(Archive & ar, const unsigned int version) { ar & BOOST_SERIALIZATION_NVP(id); ar & BOOST_SERIALIZATION_NVP(previous); ar & BOOST_SERIALIZATION_NVP(next); } }; unsigned int Node::count = 0; int _tmain(int argc, _TCHAR* argv[]) { Node *head = new Node(); Node *node = new Node(head); node = new Node(node); node = new Node(node); // serialize { ofstream ofs("cyclic.xml"); boost::archive::xml_oarchive oa(ofs); oa << BOOST_SERIALIZATION_NVP(head); } // deserialize Node *other_node = NULL; { ifstream ifs("cyclic.xml"); boost::archive::xml_iarchive ia(ifs); ia >> BOOST_SERIALIZATION_NVP(other_node); } //quit return 0; }

Hello,
I have difficulties when serializing two objects pointing to each other. The generated archive is fine (I can see both references in it), but when deserializing, only one is restored. In the attached example, I have a collection of nodes, each one is pointing to the previous and to the next node. When deserializing, only the ->next references are restored, all the ->previous are NULL.
I've stepped through your sample program in the debugger and found that this is a bug in the boost::serialization library. The problem lies in the following code from basic_archive_impl::load_pointer // if required if(track_object){ // read data state_saver<bool> x(is_object); is_object = false; // predict next object id to be created object_id_type oid(object_id_vector.size()); if(bis_ptr->tracking()) object_id_vector.push_back(aobject(t, cid)); // because the following operation could move the items // don't use co after this bisp_ptr->load_object_ptr(ar, t, co.file_version); assert(NULL != t); if(bis_ptr->tracking()){ object_id_vector[oid].address = t; // and add to list of created pointers created_pointers.push_back(created_pointer_type(cid, t)); } } This block of code is executed when an object of a certain type is deserialized through a pointer for the first time. This line object_id_vector.push_back(aobject(t, cid)); registers the object ID as stored in the archive of the to-be- deserialized object. If the same object ID is encountered later on in the deserialization process a lookup is performed in object_id_vector in order to retrieve a pointer to the previously deserialized object. Note that t in the above line of code is a reference to the pointer that will point to the object once it is deserialized. However, at the time the above line is executed t is still a NULL pointer. The object will be created in the call to load_object_ptr. In that call the object will be created and deserialized from the archive. In your sample application this will cause other objects to be deserialized that have pointer member variables pointing to the same object t points to, i.e. that have the same object ID. A lookup in object_id_vector is performed to find the corresponding pointer to the object and that pointer is used. But unfortunately, that pointer is still NULL because only after the call to load_object_ptr will the correct address be stored in the object_id_vector in this line of code: object_id_vector[oid].address = t; However, this should happen immediately after space is allocated for the object, i.e. immediately when the object's address is known and _before_ the object is deserialized. I haven't looked any more into it, but I hope it will be easy for Robert to fix. Regards, Martin TAB Austria Industrie- und Unterhaltungselektronik GmbH & CoKG http://www.tab.at
participants (2)
-
FATH Francois
-
martin.ecker@tab.at