2012-03-06 55 views
6

如何使用boost :: serialization序列化/反序列化此類?使用指針和非默認構造函數進行boost序列化

#include <vector> 

struct Foo { 
    struct Bar { 
     std::vector<int> * data; // Must point to Foo::data 

     Bar(std::vector<int> * d) : data(d) { } 
    }; 

    std::vector<int> data; 
    std::vector<Bar> elements; 

    Foo() { 
     // do very time consuming calculation to populate "data" and "elements" 
    } 
}; 

當反對從串行化的數據加載在富的構造不能被執行,但是,如果該對象是缺省構造的構造必須進行評估。

向Bar添加默認構造函數是可以的,但在序列化之後,Foo :: Bar :: data必須指向Foo :: data。

編輯:以下是我嘗試

的非工作實施這是一個基於從@Matthieu的提示我嘗試。問題是,當我反序列化Foo時,Foo :: data和Foo :: elements中沒有元素。

struct Foo { 
    struct Bar { 
     std::vector<int> * data; 

     Bar() : data(0) { } 
     Bar(std::vector<int> * d) : data(d) { } 

     template<class Archive> 
     void serialize(Archive & ar, const unsigned int version) { 
      ar & data; 
     } 
    }; 

    std::vector<int> data; 
    std::vector<Bar> elements; 

    Foo() { 
     std::cerr << "Running default constructor" << std::endl; 
     data.push_back(1); 
     data.push_back(2); 
     data.push_back(3); 
     data.push_back(4); 
     data.push_back(5); 
     elements.push_back(Bar(&data)); 
     elements.push_back(Bar(&data)); 
     elements.push_back(Bar(&data)); 
    } 

    template<class Archive> 
    Foo(Archive & ar) { 
     ar >> data; // is this corrent? 
     ar >> elements; 
    } 

private: 
    BOOST_SERIALIZATION_SPLIT_MEMBER(); 
    friend class boost::serialization::access; 

    template<class Archive> 
    void save(Archive & ar, const unsigned int version) const { 
     const std::vector<int> * data_ptr = &data; 

     // should data be seriliazed as pointer... 
     // it is used as a pointer in Bar 
     ar << data_ptr; 
     ar << elements; 
    } 
}; 

int main(int argc, const char *argv[]) 
{ 
#if 0 
    // serialize 
    Foo foo; 
    boost::archive::text_oarchive oar(std::cout); 
    oar << foo; 

#else 
    // deserialize 
    boost::archive::text_iarchive oar(std::cin); 
    Foo foo(oar); 

#endif 
    std::cerr << foo.data.size() << std::endl; 
    std::cerr << foo.elements.size() << std::endl; 

    std::cerr << (&foo.data) << std::endl; 
    for(const auto& a : foo.data) 
     std::cerr << a << " "; 
    std::cerr << std::endl; 

    for(const auto& a : foo.elements) 
     std::cerr << a.data << " "; 
    std::cerr << std::endl; 

    return 0; 
} 

回答

2

在文檔中有一節介紹如何使用非默認構造函數序列化(排序)類。見here

基本上,你必須實現兩個函數的命名空間boost::serialization寫出來並用於構建您的類的實例數據的讀取稱爲save_construct_dataload_construct_data。然後,您可以調用load_construct_data函數中的Foo的非默認構造函數,並使用重建Foo對象所需的參數。


這是基於更新的代碼工作的例子:

請注意,我用shared_ptr的澄清,由Foo和Bar序列化的data部件引用同樣的事情。

#include <vector> 
#include <boost/archive/text_oarchive.hpp> 
#include <boost/archive/text_iarchive.hpp> 
#include <boost/serialization/vector.hpp> 
#include <boost/serialization/shared_ptr.hpp> 
#include <boost/serialization/scoped_ptr.hpp> 
#include <boost/shared_ptr.hpp> 
#include <iostream> 
#include <sstream> 

struct Foo { 
    struct Bar { 
     boost::shared_ptr< std::vector<int> > data; // Must point to Foo::data 

     Bar(boost::shared_ptr< std::vector<int> > d) : data(d) { } 

     template<class Archive> 
     void serialize(Archive & ar, const unsigned int version) 
     { 
      // ** note that this is empty ** 
     } 
    }; 

    boost::shared_ptr< std::vector<int> > data; 
    std::vector<Bar> elements; 

    Foo() : data(new std::vector<int>()) { 
     std::cerr << "Running default constructor" << std::endl; 
     data->push_back(1); 
     data->push_back(2); 
     data->push_back(3); 
     data->push_back(4); 
     data->push_back(5); 
     elements.push_back(Bar(data)); 
     elements.push_back(Bar(data)); 
     elements.push_back(Bar(data)); 
    } 

    template<class Archive> 
    void serialize(Archive & ar, const unsigned int version) 
    { 
     // ** note that this is empty ** 
    } 

    Foo(
     boost::shared_ptr< std::vector<int> > const & data_, 
     std::vector<Bar> const & elements_) : data(data_), elements(elements_) 
    { 
     std::cout << "cheap construction" << std::endl; 
    } 
}; 

namespace boost { namespace serialization { 

template<class Archive> 
inline void save_construct_data(
    Archive & ar, const Foo * foo, const unsigned int file_version 
){ 
    ar << foo->data << foo->elements; 
} 

template<class Archive> 
inline void load_construct_data(
    Archive & ar, Foo * foo, const unsigned int file_version 
){ 
    boost::shared_ptr< std::vector<int> > data; 
    std::vector<Foo::Bar> elements; 

    ar >> data >> elements; 

    ::new(foo)Foo(data, elements); 
} 

template<class Archive> 
inline void save_construct_data(
    Archive & ar, const Foo::Bar * bar, const unsigned int file_version 
){ 
    ar << bar->data; 
} 

template<class Archive> 
inline void load_construct_data(
    Archive & ar, Foo::Bar * bar, const unsigned int file_version 
){ 
    boost::shared_ptr< std::vector<int> > data; 

    ar >> data; 

    ::new(bar)Foo::Bar(data); 
} 

}} 

int main() 
{ 
    std::stringstream ss; 

    { 
    boost::scoped_ptr<Foo> foo(new Foo()); 

    std::cout << "size before serialization is: " << foo->data->size() << std::endl; 

    boost::archive::text_oarchive oa(ss); 
    oa << foo; 
    } 

    { 
    boost::scoped_ptr<Foo> foo; 

    boost::archive::text_iarchive is(ss); 
    is >> foo; 

    std::cout << "size after deserialization is: " << foo->data->size() << std::endl; 
    } 

    return 0; 
} 
+0

是的,我已經看到了這一點。但是,如何編寫負載超載? Foo的默認構造函數不能被調用。 – Allan 2012-03-06 13:19:25

+0

@Allan:您需要添加一個特定於反序列化的構造函數。例如一個構造函數,它在參數中使用boost存檔。 – 2012-03-06 13:33:38

+0

@Matthieu Ahh ..儘可能簡單,謝謝。 Foo :: data怎麼樣,我應該將它序列化爲指針,然後在反序列化時進行交換? – Allan 2012-03-06 13:41:14