2012-12-27 53 views
3

我是新的C++提升,所以這個問題可能是基本的: 如何序列化是指相互指針兩班。例如:C++提高系列化類相互引用

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

特別是通過反序列化會出現問題(指針!)。有沒有想法?

回答

2

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首次遇到作爲指針。當序列化時,僅存儲對b的引用。

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

當反序列化一個,所述b將在矢量進行分配。現在你想恢復已經存在於堆棧上的b。由於您無法爲堆棧中的變量分配新地址,因此會崩潰!

正確:

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

當反序列化b,升壓只會分配b的地址一個它的載體裏面。

Boost.Serialzation還配備了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的載體(只包括頭)。

+0

我使用你的方法 A * x = new A(); B * y = new B(); x.b.push_back(y); y.a.push_back(x) 存檔<< a << b; 它仍然墜毀 A * xx B * yy 存檔>> * xx >> * yy; 我認爲這與循環引用有關。如果我使用shared_ptr,那麼沒有問題。 – user1397974

+0

@ user1397974如果這不是拼寫錯誤,它會崩潰,因爲您在反序列化時取消引用指針(基於您評論中的代碼)。使用'archive >> xx >> yy;'來代替。 –

+0

是的,你是對的。有用。非常感謝。 – user1397974

0

基本的想法是避免循環引用,因爲你的序列化會造成無限循環。

根據這一tutorial有不應與B A的實例,並給對方非循環引用任何問題。