使用boost :: serialization序列化递归图结构时如何防止堆栈溢出?

时间:2017-02-08 15:51:23

标签: c++ serialization boost graph stack-overflow

我正在尝试使用boost序列化序列化大型(几何)图形结构。

我将我的图形存储为邻接列表,也就是说,我的结构如下:

class Node {
  double x,y;
  std::vector<Node*> adjacent_nodes;
  ...
}

class Graph {
  std::vector<Node*> nodes;
  ...
}

现在使用&gt; 10k个节点我的问题是,当我开始序列化(保存)我的图形时,它会在返回之前递归调用所有这些节点的序列化,因为图形是连接的。

更准确地说,在序列化Graph时,它将通过序列化&#34;节点中的第一个节点来开始。向量。在这样做时,它需要序列化&#34; adjacent_nodes&#34;第一节点的一部分,例如,包含第二个节点。

因此,它需要在返回第一个节点的序列化之前序列化第二个节点,依此类推。

我从2010年发现了this thread,其中有人解释了完全相同的问题。但是,他们没有在那里找到有效的解决方案。

非常感谢任何帮助。

我的结构更详细:

class Node {

    double x,y;
    std::vector<Node*> adjacent_nodes;

public:

    inline double get_x() const { return x; }
    inline double get_y() const { return y; }
    inline std::vector<Node*> const& get_adjacent_nodes() const { return adjacent_nodes; }

    Node (double x, double y):x(x),y(y) {}

    void add_adjacent(Node* other) {
        adjacent_nodes.push_back(other);
    }

private:

    Node() {}

  friend class boost::serialization::access;
  template <class Archive>
  void serialize(Archive &ar, const unsigned int) {
    ar & x;
        ar & y;
        ar & adjacent_nodes;
  }

};

class Simple_graph {

std::vector<Node*> nodes;

void add_edge(int firstIndex, int secondIndex) {
    nodes[firstIndex]->add_adjacent(nodes[secondIndex]);
    nodes[secondIndex]->add_adjacent(nodes[firstIndex]);
}

public:

/* methods to get the distance of points, to read in the nodes, and to generate edges */

~Simple_graph() {
    for (auto node: nodes) {
        delete node;
    }
}

private:

  friend class boost::serialization::access;
  template <class Archive>
  void serialize(Archive &ar, const unsigned int) {
    ar & nodes;
  }

};

编辑:在上述主题中添加一些建议,引用Dominique Devienne:

  

1)在第一次传递时保存所有节点而不用它们的拓扑信息   向量,因此记录所有&#34;跟踪&#34;那么指针呢   为每个人写下拓扑信息,从那以后你就不会“re re”   只写一个&#34; ref&#34;到已经序列化的指针。

     

2)有可能写一个&#34;弱参考&#34;指针,   只添加了指向&#34;追踪&#34;用特殊标志映射   说它不是真的&#34;写的,这样写的拓扑   一个尚未编写的节点类似于&#34;前向引用&#34;至   那些相邻的节点。要么以后真的要写节点   在,或它永远不会,我想序列化应该处理   优雅。

     

#1并不需要更改boost序列化,但将责任放在客户端代码上。特别是因为你必须&#34;外部&#34;保存   邻居,所以它不再被很好地封装,并编写一个子集   表面的节点变得更加复杂。

     

#2需要提前寻找在遇到前向引用时读取实际对象,以及另外一个单独的映射   知道在哪里寻找它。这可能与助推器不相容   序列化(我承认对此几乎一无所知)。

现在可以实施这些提案吗?

2 个答案:

答案 0 :(得分:1)

由于您已经有一个带有指向所有节点的指针的向量,因此您可以使用索引序列化adjacent_nodes向量,而不是序列化实际的节点数据。

在序列化节点时,您需要将this指针转换为索引。如果您可以将节点索引存储在节点中,这是最简单的,否则您必须通过nodes搜索才能找到正确的指针(可以通过创建某种关联容器来加速此过程)指向索引的指针。)

当您需要读入数据时,您可以创建初始nodes向量,其中包含指向空/虚节点的指针(将在序列化时填充)。

如果这不可行,您可以将节点索引加载到临时数组中,然后在读入所有节点后返回并填充指针。但是您不必寻求或重新阅读文件的任何部分。

答案 1 :(得分:0)

如果图形中没有任何较大的循环,则可以按照图的“ end ”中的节点出现在矢量开头的方式对Node矢量进行排序。

示例: 假设我们有:

p1->p2->p3->....->p1000

如果您尝试序列化vector v = {p1, p2, p3, ... , p1000},将会失败 但它可以与vector v = {p1000, p999, p998, ... , p1}一起使用 但是如果你有类似的东西

p1->p2->p3->....->p1000->p1