如何使用带有嵌套结构和最少代码更改的boost :: serialization?

问题描述 投票:2回答:1

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

#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增强数据结构:

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

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

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

反对此修改的唯一论点是NewANewB不再是POD,这使得对文件的读/写更加复杂。

如何使用NewA以最小的方式将NewBboost::serialization读/写到文件代码更改为NewANewB?最小的代码更改很重要,因为例如,我们使用具有最多7个嵌套级别的大型结构。

c++ boost
1个回答
1
投票

您可以使用增强序列化¹序列化:

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方法的开箱即用的正确行为。

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

三重演示

这是一个三重演示程序,根据IMPL变量具有三种实现。

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

主程序也反序列化。

[Live On 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,就像您的类型不是POD的NSMI

© www.soinside.com 2019 - 2024. All rights reserved.