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.
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.
I had the same problem in past, and I did not find solid solution from out-of-the-box.. but the following small hack works fine - you could specify serialization and de-serialization functions separately (not using default template and &-operator):
//! Serialization
void A::serialize(xml_oarchive& ar, const unsigned int version)
{
ar << value;
}
//! De-serialization
void A::serialize(xml_iarchive& ar, const unsigned int version)
{
ar >> value;
}
And after that you could specify restoring of a pointer to parent object in deserialization method, like the following:
//! Serialization
void A::serialize(xml_oarchive& ar, const unsigned int version)
{
ar << children;
}
//! De-serialization
void A::serialize(xml_iarchive& ar, const unsigned int version)
{
ar >> children;
for(var child: children)
child->parent = this;
}
This has been resolved on the development branch.
See. https://svn.boost.org/trac/boost/ticket/9601
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With