【问题标题】:c++ boost serialization class refer to each otherc++ boost序列化类互相引用
【发布时间】:2012-12-13 06:14:27
【问题描述】:

我是 C++ boost 新手,所以这个问题可能很基础: 如何序列化两个用指针相互引用的类。例如:

class A;
class B;

class A {
  public:
  ...
  private:
    double a;
    vector <B*> b;
}

class B {
  public:
  ...
  private:
    int b;
    list <A*> a;
}

A 类有一个包含指针 B* 的私有向量,而 B 类有一个包含 A* 的私有列表。

尤其是反序列化会有问题(指针!)。有人知道吗?

【问题讨论】:

    标签: c++ boost-serialization


    【解决方案1】:

    Boost.Serialization 可以很好地处理指针的循环引用,这要感谢object tracking。 如果通过指针序列化对象,则默认使用对象跟踪。它还带有std::vector 的序列化程序(包括boost/serialization/vector.hpp)。

    Boost.Serialzation 将跟踪您序列化的对象的地址。 如果它遇到一个已经序列化的地址,它将存储一个对对象的“引用”而不是再次序列化它。

    在反序列化时,它会在遇到这些引用时将它们解析为正确的地址(这意味着它们必须是指针,以便可以将地址分配给它们)。

    唯一的限制是,引用的对象必须动态分配(在堆上)。你可以序列化堆栈上的一个对象,只要它没有被另一个对象引用。

    A a;
    B b;
    a.vec.push_back( &b ); // WRONG! deserialization will crash
    // if a does not reference to b, it will work
    archive << a << b;
    

    原因是:b 在序列化 a(在其向量中)时首先作为指针遇到。序列化 b 本身时,只存储对 b 的引用。

    A a;
    B b;
    archive >> a >> b; // crashes when deserializing b!
    

    在反序列化a时,b会被分配到vector中。现在你想恢复堆栈中已经存在的 b 。由于不能给栈上的变量分配新地址,所以会崩溃!

    正确:

    A* a = new A();
    B* b = new B();
    a.vec.push_back(b); // OK! this works fine
    

    当反序列化b时,boost会简单的将a的向量内的b的地址分配给它。

    Boost.Serialzation 还附带了一个用于boost::shared_ptr(包括boost/serialization/shared_ptr.hpp)的序列化程序,它可以通过以下方式使您的任务更加轻松 改为使用std::vector&lt; boost::shared_ptr&lt;A&gt; &gt;,这样您就不必担心释放内存。

    有了基础知识,您就可以像这样简单地实现类的序列化:

    // add this to your classes you want to serialize
    private:
        friend boost::serialization::access;
        template<class Archive>
        void serialize(Archive& ar, unsigned version) {
            //TODO: serialize other member variables
            ar & BOOST_SERIALIZATION_NVP(vec); // vec is a std::vector
        }
    

    如果您选择使用 shared_ptrs 的向量(仅包含标题),则无需更改。

    【讨论】:

    • 我用你的方法 A *x = new A(); B *y = 新 B(); x.b.push_back(y); y.a.push_back(x) 存档 > *xx >> *yy; 时它仍然崩溃;我认为这与循环引用有关。如果我使用shared_ptr,那么没有问题。
    • @user1397974 如果这不是错字,它会崩溃,因为您在反序列化时取消引用指针(基于您评论中的代码)。请改用archive &gt;&gt; xx &gt;&gt; yy;
    【解决方案2】:

    基本思路是避免yclic引用,因为你的序列化会造成无限循环。

    根据tutorial,A 和 B 的实例相互之间的非循环引用应该没有任何问题。

    【讨论】:

      猜你喜欢
      • 2019-05-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-16
      • 2011-04-09
      • 2022-12-02
      • 1970-01-01
      相关资源
      最近更新 更多