[英]Boost serialization with pointers and non-default constructor
How would you serialize/deserialize this class using boost::serialization? 你会如何使用boost :: serialization序列化/反序列化这个类?
#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"
}
};
The constructor in Foo must not be executed when the objected is loaded from the serialized data, but if the object is default constructed the constructor must be evaluated. 当从序列化数据加载对象时,不得执行Foo中的构造函数,但如果对象是默认构造的,则必须对构造函数进行求值。
It is okay to add a default constructor to Bar, but after serialization the Foo::Bar::data must point to the Foo::data. 可以向Bar添加默认构造函数,但在序列化之后,Foo :: Bar :: data必须指向Foo :: data。
EDIT: Following is a non-working implementation of my attempt 编辑:以下是我的尝试的非工作实现
This is my attempt based on the hints from @Matthieu. 这是我基于@Matthieu提示的尝试。 The problem is that when I deserialize Foo, I get no elements in Foo::data and Foo::elements. 问题是,当我反序列化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;
}
There is a section in the documentation that describes how to (de)serialize classes with non-default constructors. 文档中有一节描述如何(de)使用非默认构造函数序列化类。 See here . 看到这里 。
Basically, you must implement two functions called save_construct_data
and load_construct_data
in the namespace boost::serialization
to write out and read in the data used to construct instances of your class. 基本上,您必须在命名空间boost::serialization
实现名为save_construct_data
和load_construct_data
两个函数,以写出并读入用于构造类实例的数据。 You can then call a non-default constructor of Foo
from the load_construct_data
function with the parameters necessary to reconstruct a Foo
object. 然后,您可以使用重建Foo
对象所需的参数从load_construct_data
函数调用Foo
的非默认构造函数。
Here is a working example based on your updated code: 这是一个基于您更新的代码的工作示例:
Note that I've used shared_ptr
's to clarify that the data
member serialized by Foo and Bar are referencing the same thing. 请注意,我已经使用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;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.