当前,我们使用存储在嵌套结构中的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 = {};
}
反对此修改的唯一论点是NewA
和NewB
不再是POD,这使得对文件的读/写更加复杂。
如何使用NewA
以最小的方式将NewB
和boost::serialization
读/写到文件代码更改为NewA
和NewB
?最小的代码更改很重要,因为例如,我们使用具有最多7个嵌套级别的大型结构。
您可以使用增强序列化¹序列化:
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方法有所了解,请参阅C++ Boost::serialization : How do I archive an object in one program and restore it in another?)
²不是POD,就像您的类型不是POD的NSMI