boost::serialization and cyclic reference deserialization
boost, c++, c++11, serialization
Solution
Alright, apparently I fell prey to another unlucky bug. Boost 1.55 doesn't yet have a working serialization library for VS2013, according to the latest Boost release page. Talk about wasted time...
Known Bugs with Visual Studio 2013/Visual C++ 12
Visual Studio 2013 was released quite late in the release process, so there exist several unresolved issues. These include:
Serialization can't compile because of a missing include.
Problem
I have a tree-like structure that needs to be serialized. Typical structure, with each node having `parent` members and `children` vectors. `parent` is a raw pointer-to-class, and `children` are `vector`s of `shared_ptr`s. Now it seems that serialization works fine, but de-serialization leaves the `parent` members uninitialized (pointers to `0xcccccccc` or `0x00000000`). The `parent` members are being loaded when the actual parent object has not yet finished deserializing, i.e. the child's `parent` member is loaded through the deserialization request of the parent's `children`. Since this is cyclic I was wondering whether I need to take special measures for it to work. Thanks for the help. Update: This is how my serializing function looks like: ``` template <typename Archive> void serialize(Archive& archive, GameCore::GameObject& t, const unsigned int version) { archive & boost::serialization::base_object<GameCore::Object>(t); archive & boost::serialization::base_object<GameCore::Updatable>(t); archive & t.parent; archive & t.transform; archive & t.components; archive & t.children; } ``` If I comment out `archive & t.children`, `parent` gets populated correctly. Update 2: Ok, I've managed to turn this into a minimal sample that exhibits the problem. The following should compile: ``` #include <boost\archive\binary_oarchive.hpp> #include <boost\archive\binary_iarchive.hpp> #include <fstream> #include <memory> #include <vector> class A { public: A() {} A(const A& rhs) = delete; int someInt = 0; A* parent = nullptr; std::vector<A*> children; template <class Archive> void serialize(Archive& archive, const unsigned int version) { archive & someInt; archive & parent; int count = children.size(); archive & count; children.resize(count); for (int i = 0; i < count; ++i) { A* ptr = children[i]; archive & ptr; children[i] = ptr; } } }; int main() { A* newA = new A(); newA->someInt = 0; A* newPtr = new A(); newPtr->someInt = 5; newPtr->parent = newA; newA->children.push_back(newPtr); // Save. std::ofstream outputFile("test", std::fstream::out | std::fstream::binary); if (outputFile.is_open()) { boost::archive::binary_oarchive outputArchive(outputFile); // Serialize objects. outputArchive << newA; outputFile.close(); } delete newA; delete newPtr; A* loadedPtr = nullptr; // Load. std::ifstream inputFile("test", std::fstream::binary | std::fstream::in); if (inputFile && inputFile.good() && inputFile.is_open()) { boost::archive::binary_iarchive inputArchive(inputFile); // Load objects. inputArchive >> loadedPtr; inputFile.close(); } return 0; } ``` Step through the code. The child's `parent` stays null, always.