升压序列化指针和非默认构造函数 [英] Boost serialization with pointers and non-default constructor

查看:128
本文介绍了升压序列化指针和非默认构造函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

你会如何序列化/使用boost ::序列化反序列化这个类?

 的#include<矢量>结构美孚{
    结构酒吧{
        的std ::矢量<&INT GT; *数据; //必须指向富::数据        酒吧(的std ::矢量<&INT GT; * D):数据(D){}
    };    的std ::矢量<&INT GT;数据;
    的std ::矢量<酒吧GT;要素;    美孚(){
        //做的非常耗时的计算来填充数据和元素
    }
};

当反对从序列化的数据加载在富的构造必须不被执行,但是,如果该对象是缺省构造的构造,必须进行评估。

这是好到一个默认的构造函数添加到酒吧,但序列化后富::酒吧::数据必须指向富::数据。

编辑:以下是我尝试的非工作实现

这是基于从@Matthieu的提示我尝试。问题是,当我反序列化富,我得到了美孚::数据与富::元素没有元素。

 结构美孚{
    结构酒吧{
        的std ::矢量<&INT GT; *数据;        酒吧():数据(0){}
        酒吧(的std ::矢量<&INT GT; * D):数据(D){}        模板<类归档和GT;
        无效连载(归档和放大器; AR,const的无符号整型版){
            AR&安培;数据;
        }
    };    的std ::矢量<&INT GT;数据;
    的std ::矢量<酒吧GT;要素;    美孚(){
        的std :: CERR<< 运行默认构造函数<<的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(栏(&放大器;数据));
        elements.push_back(栏(&放大器;数据));
        elements.push_back(栏(&放大器;数据));
    }    模板<类归档和GT;
    美孚(归档和放大器; AR){
        AR>>数据; //这是corrent?
        AR>>要素;
    }私人的:
    BOOST_SERIALIZATION_SPLIT_MEMBER();
    友元类的boost ::系列化::访问;    模板<类归档和GT;
    无效保存(归档和放大器; AR,const的无符号整型版)常量{
        常量的std ::矢量<&INT GT; * DATA_PTR =放大器;数据;        //应数据seriliazed为指针...
        //它被用作酒吧指针
        AR<< DATA_PTR;
        AR<<要素;
    }
};INT主(INT ARGC,为const char * argv的[])
{
#如果0
    //连载
    富富;
    提高::档案:: text_oarchive的桨(标准::法院);
    桨<<富;#其他
    //反序列化
    提高::档案:: text_iarchive桨(的std :: CIN);
    富富(桨);#万一
    的std :: CERR<< foo.data.size()&所述;&下;的std :: ENDL;
    的std :: CERR<< foo.elements.size()&所述;&下;的std :: ENDL;    的std :: CERR<< (安培; foo.data)LT;<的std :: ENDL;
    对于(const的汽车和放大器;一个:foo.data)
        的std :: CERR<< A<< ;
    的std :: CERR<<的std :: ENDL;    对于(const的汽车和放大器;一个:foo.elements)
        的std :: CERR<< A.数据<< ;
    的std :: CERR<<的std :: ENDL;    返回0;
}


解决方案

有是介绍如何(反)序列化与非默认构造类的文档中的一个部分。请参见这里

基本上,你必须实现两个函数,叫 save_construct_data load_construct_data 命名空间中的提振::系列化写出来,并用于构建您的类的实例数据的读取。然后,您可以调用从 load_construct_data 函数的非默认构造函数必要重建参数对象。


下面是根据更新后的code工作的例子:

请注意,我用的澄清,由Foo和Bar序列化的数据成员是的shared_ptr 引用同样的事情。

 的#include<矢量>
#包括LT&;升压/存档/ text_oarchive.hpp>
#包括LT&;升压/存档/ text_iarchive.hpp>
#包括LT&;升压/系列化/ vector.hpp>
#包括LT&;升压/系列化/ shared_ptr.hpp>
#包括LT&;升压/系列化/ scoped_ptr.hpp>
#包括LT&;升压/ shared_ptr.hpp>
#包括LT&;&iostream的GT;
#包括LT&;&sstream GT;结构美孚{
    结构酒吧{
        提高:: shared_ptr的<的std ::矢量<&INT GT; >数据; //必须指向富::数据        酒吧(提高:: shared_ptr的<的std ::矢量<&INT GT;> D):数据(D){}        模板<类归档和GT;
        无效连载(归档和放大器; AR,const的无符号整型版)
        {
          // **注意,这是空**
        }
    };    提高:: shared_ptr的<的std ::矢量<&INT GT; >数据;
    的std ::矢量<酒吧GT;要素;    美孚():数据(新的std ::矢量<&INT GT;()){
        的std :: CERR<< 运行默认构造函数<<的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(栏(数据));
        elements.push_back(栏(数据));
        elements.push_back(栏(数据));
    }    模板<类归档和GT;
    无效连载(归档和放大器; AR,const的无符号整型版)
    {
      // **注意,这是空**
    }    美孚(
      提高:: shared_ptr的<的std ::矢量<&INT GT; >常量和放大器;数据_,
      的std ::矢量<酒吧GT;常量和放大器; elements_):数据(data_中的数据),元件(elements_)
    {
        性病::法院LT&;< 便宜建设<<的std :: ENDL;
    }
};名字空间boost {空间序列{模板<类归档和GT;
内嵌无效save_construct_data(
    归档和放大器; AR,常量富*富,const的无符号整型FILE_VERSION
){
    AR<< foo->数据<< foo->要素;
}模板<类归档和GT;
内嵌无效load_construct_data(
    归档和放大器; AR,富富*,const的无符号整型FILE_VERSION
){
    提高:: shared_ptr的<的std ::矢量<&INT GT; >数据;
    的std ::矢量<富::酒吧GT;要素;    AR>>数据>>要素;    ::新的(富)富(数据元素);
}模板<类归档和GT;
内嵌无效save_construct_data(
    归档和放大器; AR,常量富::酒吧*酒吧,const的无符号整型FILE_VERSION
){
    AR<<酒吧,>数据;
}模板<类归档和GT;
内嵌无效load_construct_data(
    归档和放大器; AR,富::酒吧*酒吧,const的无符号整型FILE_VERSION
){
    提高:: shared_ptr的<的std ::矢量<&INT GT; >数据;    AR>>数据;    ::新(巴)富::酒吧(数据);
}}}诠释的main()
{
  的std :: stringstream的SS;  {
    提高:: scoped_ptr的<美孚>美孚(新富());    性病::法院LT&;< 串行化之前的大小是:<< foo->数据 - >大小()<<的std :: ENDL;    提高::档案:: text_oarchive的OA(SS);
    OA<<富;
  }  {
    提高:: scoped_ptr的<美孚>富;    提高::档案:: text_iarchive是(SS);
    是>>富;    性病::法院LT&;< 反序列化后的大小是:<< foo->数据 - >大小()<<的std :: ENDL;
  }  返回0;
}

How would you serialize/deserialize this class using 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.

It is okay to add a default constructor to Bar, but after serialization the Foo::Bar::data must point to the Foo::data.

EDIT: Following is a non-working implementation of my attempt

This is my attempt based on the hints from @Matthieu. The problem is that when I deserialize Foo, I get no elements in Foo::data and 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. 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. 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.


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.

#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;
}

这篇关于升压序列化指针和非默认构造函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆