2012-03-06 75 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