views:

77

answers:

2

I have to serialize libkdtree++ in my program, the tree structures are briefly described as following:

struct _Node_base {
  _Node_base * _M_parent, *_M_left, * _M_right;

  template<Archive>
  serialize(Archive &ar, const unsigned int version) {
    ar & _M_left & _M_right;
  }
}

template<typename V>
struct _Node : public _Node_base {
  typedef V value_type;
  value_type value;
  template<Archive>
  serialize(Archive &ar, const unsigned int version) {
    ar.register_type(static_cast<_Node*>(NULL));
    ar & boost::serialization::base_object<_Node_base>(*this);
    ar & value;
  }
}

struct Tree {
  _Node * root;
  template<Archive>
  serialize(Archive &ar, const unsigned int version) {
    ar & root;
  }
}

This program reports "stream error". But from the "serailzed file", it lacks the value fields for the children nodes of roots. Thus I think it is possible that BaseNode serialized _M_left and _M_right pointer. However since _Node_base have no idea about the value type of _Node, so it looks hard to add "ar.register_type" to _Node_base.serialize().

A: 

The pointer_conflict exception documentation states (sic):

    pointer_conflict,   // an attempt has been made to directly
                        // serialization::detail an object
                        // after having already serialzed the same
                        // object through a pointer.  Were this permited,
                        // it the archive load would result in the
                        // creation of an extra copy of the obect.

I think the conflict occurs where each is serialised by a ptr in BaseNode::serialize and via the direct object, the *Node expression, in Node::serialize. However since the base_object function takes a reference and not a ptr I'm not sure how you would avoid this.

One possibility is to not serialize the parent ptr. Instead, after deserialization, do a walk of the tree and fix up the parent ptrs to point to the node parent. E.g. add the following method to BaseNode :

void fix (BaseNode* parent = 0)
{
    this->parent = parent;
    if (left != 0)
        left->fix (this);
    if (right != 0)
        right->fix (this);
}

Then just call root->fix ()

jon hanson
It still has a stream error raised from decoding process...I am figuring it
eddyxu
friend class boost::serialization::access; template<class Archive> void serialize(Archive ar ar }I added this function into libkdtree::_Node, however, I think the problem here is the serialize() function in base_object would not serialize the _left, _right point correctly, which just treat them as _Node_base * pointer
eddyxu
A: 

The following solution for libkdtree++ & boost::serialization seems work:

// KDTree::_Node
friend class boost::serialization::access;
template<class Archive>
//void serialize(Archive & ar, const unsigned int version)
void save(Archive & ar, const unsigned int version) const
{
  ar.register_type(static_cast< _Link_type>(NULL));
  ar & boost::serialization::base_object<_Node_base>(*this);
  _Link_type left = static_cast<_Link_type>(_M_left);
  _Link_type right = static_cast<_Link_type>(_M_right);
  ar & left & right;
  ar & _M_value;
}


template<class Archive>
void load(Archive & ar, const unsigned int version)
{
    ar.register_type(static_cast< _Link_type>(NULL));
    ar & boost::serialization::base_object<_Node_base>(*this);
    _Link_type left, right;
    ar & left & right;
    ar & _M_value;
    if (left) {
       left->_M_parent = this;
    } 
    if (right) {
       right->_M_parent = this;
    }
    _M_left = left;
    _M_right = right;
}

BOOST_SERIALIZATION_SPLIT_MEMBER()
eddyxu
I put my solution on http://github.com/eddyxu/kdtree-serialization
eddyxu