c++ - 使用指针和非默认构造函数 boost 序列化

标签 c++ boost 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"
    }
};

当从序列化数据加载对象时,不得执行 Foo 中的构造函数,但如果对象是默认构造的,则必须评估构造函数。

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

最佳答案

文档中有一节描述了如何使用非默认构造函数(反)序列化类。参见 here .

基本上,您必须在命名空间boost::serialization 中实现名为save_construct_dataload_construct_data 的两个函数来写入和读取数据用于构造类的实例。然后,您可以使用重建 Foo 对象所需的参数从 load_construct_data 函数调用 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;
}

关于c++ - 使用指针和非默认构造函数 boost 序列化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9584296/

相关文章:

c++ - 如何将 WndProc 用作类函数

c++ - 我如何在 SQLITE C++ 中保存结构

c# - C++中的字符串?

c++ - CMake:使用项目安装 boost 组件库的正确方法

c++ - boost : problems with placement new 中的 load_construct_data

c++ - 在集群上加载库

c++ - 使用闭源库 boost 分布式

c++ - boost::transform 与 std::transform

android - 使用 boost 编译 android 应用程序,未定义对 'mbtowc' 的引用

c++ - boost 序列化 binary_oarchive 崩溃