Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

boost::serialization and cyclic reference deserialization

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 vectors of shared_ptrs. 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.

like image 443
Kristian D'Amato Avatar asked Nov 25 '13 00:11

Kristian D'Amato


3 Answers

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.

like image 96
Kristian D'Amato Avatar answered Sep 26 '22 02:09

Kristian D'Amato


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;
}
like image 30
inf581 Avatar answered Sep 24 '22 02:09

inf581


This has been resolved on the development branch.

See. https://svn.boost.org/trac/boost/ticket/9601

like image 26
Brandon Kohn Avatar answered Sep 26 '22 02:09

Brandon Kohn