2012-03-06 2 views
6

부스트 :: 직렬화를 사용하여이 클래스를 직렬화/역 직렬화 하시겠습니까?포인터 및 기본이 아닌 생성자를 사용하여 직렬화 부스트

#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를 deserialize 할 때 Foo :: data와 Foo :: 요소에 요소가 없다는 것입니다.

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이라는 두 가지 기능을 구현하여 클래스 인스턴스를 작성하는 데 사용되는 데이터를 작성하고 읽어야합니다. 그런 다음 Foo 객체를 재구성하는 데 필요한 매개 변수를 사용하여 load_construct_data 함수에서 Foo의 기본값이 아닌 생성자를 호출 할 수 있습니다. 내가 푸와 바 직렬화 data 구성원이 같은 일을 참조하고 있음을 명확히하기 위해 shared_ptr 's을 (를) 사용했습니다

참고 : 여기에


는 업데이트 된 코드를 기반으로 작동하는 예이다.

#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

+0

@Allan : 비 직렬화를위한 생성자를 추가해야합니다. 예를 들어 인수에서 부스트 아카이브를 사용하는 생성자. –

+0

@Matthieu Ahh .. 이것처럼 간단합니다, 고마워요. Foo :: data는 포인터로 직렬화해야하며 직렬화 해제 할 때 스왑을 수행해야합니까? – Allan

관련 문제