[英]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.反对这种修改的唯一理由是
NewA
和NewB
不再是 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
?这怎么可能读/写
NewA
和NewB
使用到文件boost::serialization
用最少的代码改变NewA
和NewB
? 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
:它会跟踪当前的大小,但数据是在结构内部静态分配的。
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.主程序也反序列化。
#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
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.