如何使用带有嵌套结构和最少代码更改的boost :: serialization? [英] How to use boost::serialization with nested structs and minimal code changes?

查看:102
本文介绍了如何使用带有嵌套结构和最少代码更改的boost :: serialization?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当前,我们使用存储在嵌套结构中的POD.示例:

Currently we use POD which is stored in nested structs. Example:

#define MaxNum1 100;
#define MaxNum2 50;

struct A
{
    int Value[MaxNum1]; 
    char SomeChar = 'a';
};

struct B
{
    A data[MaxNum2];
    float SomeFloat = 0.1f;
};


int main()
{
    B StructBObject = {};
}

我们想使用std :: vector来增强数据结构,就像这样:

We want to enhance our data structures using std::vector just like this:

struct NewA
{
    std::vector<int> Value; 
    char SomeChar = 'a';
};

struct NewB
{
    std::vector<NewA> data;
    float SomeFloat = 0.1f;
};

int main()
{
    NewB StructNewBObject = {};
}

反对此修改的唯一论点是 NewA NewB 不再是POD,这使得对文件的读取/写入更加复杂.

The only argument against this modification is that NewA and NewB are no POD anymore and this makes reading/writing to a file more complicated.

如何尽可能少地使用 boost :: serialization NewA NewB 读/写到文件中代码更改为 NewA NewB ?最小的代码更改很重要,因为我们使用的是例如具有多达7个嵌套级别的大型结构.

How is it possible to read/write NewA and NewB to a file using boost::serialization with minimal code changes to NewA and NewB? Minimal code changes are important because we use for example big structs which have up to 7 nested levels.

推荐答案

您可以使用boost序列化¹进行序列化:

You can serialize using boost serialization¹:

template <typename Ar> void serialize(Ar& ar, A& a, unsigned) {
    ar & a.Value & a.SomeChar;
}
template <typename Ar> void serialize(Ar& ar, B& b, unsigned) {
    ar & b.data & b.SomeFloat;
}

使用这些方法,您将已经使用C数组和std :: vector方法具有开箱即用的正确行为.

Using these, you will already have the correct behaviour out of the box with both the C-array and std::vector approaches.

如果您想继续使用固定大小的平凡可复制类型²,则可以使用Boost Container的 static_vector 之类的东西:它将跟踪当前大小,但是数据静态地分配在内部结构.

If you want to keep using fixed-size trivially-copyable types², you can use something like Boost Container's static_vector: it will keep track of the current size, but the data is statically allocated right inside the structures.

这是一个三重演示程序,具有三个实现,具体取决于 IMPL 变量.

Here's a triple demo program with three implementations depending on the IMPL variable.

如您所见,大部分代码保持不变.但是,为了进行最佳比较",我确保在序列化之前所有容器的容量均为一半(50/25).

As you can see the bulk of the code is kept invariant. However, for "best comparison" I've made sure that all the containers are at half capacity (50/25) before serialization.

主程序也会反序列化.

在Coliru上直播

#include <boost/iostreams/device/back_inserter.hpp>
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/stream.hpp>

#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>

#include <boost/serialization/access.hpp>
#include <boost/serialization/is_bitwise_serializable.hpp>
#include <boost/serialization/binary_object.hpp>

#include <iostream>

#if (IMPL==0) // C arrays
    struct A {
        int Value[100]; 
        char SomeChar = 'a';
    };

    struct B {
        A data[50];
        float SomeFloat = 0.1f;
    };

    template <typename Ar> void serialize(Ar& ar, A& a, unsigned) {
        ar & a.Value & a.SomeChar;
    }
    template <typename Ar> void serialize(Ar& ar, B& b, unsigned) {
        ar & b.data & b.SomeFloat;
    }

#elif (IMPL==1) // std::vector
    #include <boost/serialization/vector.hpp>
    struct A {
        std::vector<int> Value;
        char SomeChar = 'a';
    };

    struct B {
        std::vector<A> data;
        float SomeFloat = 0.1f;
    };

    template <typename Ar> void serialize(Ar& ar, A& a, unsigned) {
        ar & a.Value & a.SomeChar;
    }
    template <typename Ar> void serialize(Ar& ar, B& b, unsigned) {
        ar & b.data & b.SomeFloat;
    }

#elif (IMPL==2) // static_vector
    #include <boost/serialization/vector.hpp>
    #include <boost/container/static_vector.hpp>
    struct A {
        boost::container::static_vector<int, 100> Value; 
        char SomeChar = 'a';
    };

    struct B {
        boost::container::static_vector<A, 50> data; 
        float SomeFloat = 0.1f;
    };

    template <typename Ar> void serialize(Ar& ar, A& a, unsigned) {
        ar & boost::serialization::make_array(a.Value.data(), a.Value.size()) & a.SomeChar;
    }
    template <typename Ar> void serialize(Ar& ar, B& b, unsigned) {
        ar & boost::serialization::make_array(b.data.data(), b.data.size()) & b.SomeFloat;
    }

#endif

namespace bio = boost::iostreams;
static constexpr auto flags = boost::archive::archive_flags::no_header;
using BinaryData = std::vector</*unsigned*/ char>;

int main() {
    char const* impls[] = {"C style arrays", "std::vector", "static_vector"};
    std::cout << "Using " << impls[IMPL] << " implementation: ";
    BinaryData serialized_data;

    {
        B object = {};
#if IMPL>0
        {
            // makes sure all containers half-full
            A element;
            element.Value.resize(50);
            object.data.assign(25, element);
        }
#endif

        bio::stream<bio::back_insert_device<BinaryData>> os { serialized_data };
        boost::archive::binary_oarchive oa(os, flags);

        oa << object;
    }

    std::cout << "Size: " << serialized_data.size() << "\n";

    {
        bio::array_source as { serialized_data.data(), serialized_data.size() };
        bio::stream<bio::array_source> os { as };
        boost::archive::binary_iarchive ia(os, flags);

        B object;
        ia >> object;
    }
}

打印

Using C style arrays implementation: Size: 20472
Using std::vector implementation: Size: 5256
Using static_vector implementation: Size: 5039

最终思想

另请参阅:

¹(但请牢记可移植性,您可能已经对POD方法有所了解,请参阅

¹ (but keep in mind portability, as you probably already are aware with the POD approach, see C++ Boost::serialization : How do I archive an object in one program and restore it in another?)

²不是POD,就像您的类型不是POD的NSMI

² not POD, as with the NSMI your types weren't POD

这篇关于如何使用带有嵌套结构和最少代码更改的boost :: serialization?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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