C ++ Boost сериализации класс ссылаются друг на друга

Я новичок в 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

Решение

Boost.Serialization отлично справится с круговыми ссылками указателей, благодаря отслеживание объекта.
Если вы сериализуете объект через указатель, по умолчанию используется отслеживание объекта. Он также поставляется с сериализатором для std::vector (включают boost/serialization/vector.hpp).

Boost.Serialization будет отслеживать адреса объектов, которые вы сериализуете.
Если он встречает адрес, который уже был сериализован, он будет хранить «ссылку» на объект, а не сериализовать его снова.

При десериализации он разрешает эти ссылки на соответствующие адреса при их обнаружении (что означает, что они должны быть указателями, чтобы им можно было назначать адреса).

Единственное ограничение заключается в том, что ссылочные объекты должны размещаться динамически (в куче). Вы можете сериализовать объект в стеке, если на него не ссылается другой объект.

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 a;
B b;
archive >> a >> b; // crashes when deserializing b!

При десериализации , б будет выделяться в векторе. И теперь вы хотите восстановить б который уже существует в стеке. Так как вы не можете назначить новый адрес переменной в стеке, он потерпит крах!

Правильный:

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

При десериализации б, Boost просто назначит адрес б внутри вектора к этому.

Boost.Serialization также поставляется с сериализатором для boost::shared_ptr (включают 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 (просто включите заголовок).

3

Другие решения

Основная идея состоит в том, чтобы избежать yclic ссылок, потому что ваша сериализация сделает бесконечный цикл.

Согласно этому руководство не должно быть никаких проблем с ациклическими ссылками экземпляров A и B друг на друга.

0