简体   繁体   English

如何将 boost::serialization 与嵌套结构和最少的代码更改一起使用?

[英]How to use boost::serialization with nested structs and minimal code changes?

Currently we use POD which is stored in nested structs.目前我们使用存储在嵌套结构中的 POD。 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 = {};
}

We want to enhance our data structures using std::vector just like this:我们想使用 std::vector 来增强我们的数据结构,就像这样:

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

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

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

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.反对这种修改的唯一理由是NewANewB不再是 POD,这使得读取/写入文件更加复杂。

How is it possible to read/write NewA and NewB to a file using boost::serialization with minimal code changes to NewA and NewB ?这怎么可能读/写NewANewB使用到文件boost::serialization用最少的代码改变NewANewB Minimal code changes are important because we use for example big structs which have up to 7 nested levels.最少的代码更改很重要,因为我们使用例如具有多达 7 个嵌套级别的大结构。

You can serialize using boost serialization¹:您可以使用 boost 序列化¹进行序列化:

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

Using these, you will already have the correct behaviour out of the box with both the C-array and std::vector approaches.使用这些,您将已经拥有 C 数组和 std::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.如果你想继续使用固定大小的普通可复制类型²,你可以使用类似 Boost Container 的static_vector :它会跟踪当前的大小,但数据是在结构内部静态分配的。

TRIPLE DEMO三重演示

Here's a triple demo program with three implementations depending on the IMPL variable.这是一个三重演示程序,其中包含三个取决于IMPL变量的实现。

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.但是,为了“最佳比较”,我已确保所有容器在序列化之前都处于一半容量 (50/25)。

The main program also deserializes.主程序也反序列化。

Live On Coliru 住在 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;
    }
}

Printing印刷

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

Final Thoughts最后的想法

See also:也可以看看:


¹ (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 方法,请参阅C++ Boost::serialization : How do I archive a object in a program and restore it in another?

² not POD, as with the NSMI your types weren't POD ² 不是 POD,与 NSMI 一样,您的类型不是 POD

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM