4

我是 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* 的私有列表。

特别是通过反序列化会有问题(指针!)。有没有人有想法?

4

2 回答 2

3

Boost.Serialization 将很好地处理指针的循环引用,这要归功于对象跟踪。如果通过指针序列化对象,则默认使用对象跟踪。它还带有一个用于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;

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

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

反序列化a时,b将分配在向量中。现在您要恢复堆栈中已经存在的b 。由于您无法为堆栈上的变量分配新地址,因此它将崩溃!

正确的:

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

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

Boost.Serialzation 还附带了一个用于boost::shared_ptr(include boost/serialization/shared_ptr.hpp) 的序列化程序,使用它可以使您的任务更加轻松,std::vector< boost::shared_ptr<A> >因此您不必担心释放内存。

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

// 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 的向量(仅包括标题),则无需进行任何更改。

于 2012-12-27T23:53:20.517 回答
0

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

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

于 2012-12-27T23:09:07.813 回答