提升序列化:从版本化 class 到 object_serializable 的过渡
Boost Serialization: Transition from versioned class to object_serializable
TLDR:我想将 class 序列化从实现级别 object_class_info
过渡到 object_serializable
,保持与旧数据文件的兼容性,同时始终以新格式写入文件。
理由:当我开始使用 Boost 序列化库时,我没有意识到它已经带有一个头文件 (complex.hpp) 来序列化 std::complex<double>
。相反,我编写了自己的独立序列化函数:
namespace boost { namespace serialization {
template<class Archive, typename T>
void serialize(Archive& ar, std::complex<T>& comp, const unsigned int version) {
ar & reinterpret_cast<T(&)[2]>(comp)[0];
ar & reinterpret_cast<T(&)[2]>(comp)[1];
}
}
这默认启用版本和 class 信息跟踪,这会大大降低代码速度。 Boost自带的序列化函数要快一些。
我现在想在写出新数据文件时始终转换为使用 Boost 版本,但仍然能够读取旧数据文件。使用旧二进制文件读取新文件不是问题。
问题是新的序列化没有版本化(很明显)。此外,我什至不知道如何尝试使用旧版本的代码读取存档并立即使用新版本再次将其写出,因为 deserialisation/serialisation 特征是全局属性。
a) 透明地读入旧文件和新文件,同时始终写入新文件,或者 b) 读入旧文件并立即以新格式写出的最佳方法是什么?
如果文件版本为"old",您可以保留旧的实现并使用它。
仅在保存或文件版本为"new"时使用复杂序列化的boost版本。
如果您有一个包含要序列化的复杂数据的对象,这应该是微不足道的,因为可以通过改变包含对象的版本来实现这一点
更新
示例,使用简单的包装器调用旧式序列化:
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/complex.hpp>
template <typename T> struct old_format_wrapper {
T& wrapped;
old_format_wrapper(T& w) : wrapped(w) {}
};
template <typename T>
old_format_wrapper<T> old_format(T& w) { return {w}; }
namespace boost { namespace serialization {
template<class Archive, typename T>
void serialize(Archive& ar, old_format_wrapper<std::complex<T> >& comp, unsigned) {
ar & reinterpret_cast<T(&)[2]>(comp.wrapped)[0];
ar & reinterpret_cast<T(&)[2]>(comp.wrapped)[1];
}
} }
struct IHaveComplexData {
std::complex<double> data;
template <typename Ar> void serialize(Ar& ar, unsigned version) {
switch(version) {
case 0: { // old
auto wrap = old_format(data);
ar & wrap;
}
break;
case 1: // new
default:
ar & data; // uses boost serialization
break;
}
}
};
int main() {
{
boost::archive::text_oarchive oa(std::cout);
IHaveComplexData o { { 2, 33 } };
oa << o;
}
{
std::istringstream iss("22 serialization::archive 13 0 0 0 0 2.00000000000000000e+00 3.30000000000000000e+01");
boost::archive::text_iarchive ia(iss);
IHaveComplexData o;
ia >> o;
std::cout << o.data;
}
}
打印(取决于您的 boost 版本):
22 serialization::archive 13 0 0 0 0 2.00000000000000000e+00 3.30000000000000000e+01
(2,33)
当然你现在可以设置BOOST_CLASS_VERSION(IHaveComplexData, 1)
TLDR:我想将 class 序列化从实现级别 object_class_info
过渡到 object_serializable
,保持与旧数据文件的兼容性,同时始终以新格式写入文件。
理由:当我开始使用 Boost 序列化库时,我没有意识到它已经带有一个头文件 (complex.hpp) 来序列化 std::complex<double>
。相反,我编写了自己的独立序列化函数:
namespace boost { namespace serialization {
template<class Archive, typename T>
void serialize(Archive& ar, std::complex<T>& comp, const unsigned int version) {
ar & reinterpret_cast<T(&)[2]>(comp)[0];
ar & reinterpret_cast<T(&)[2]>(comp)[1];
}
}
这默认启用版本和 class 信息跟踪,这会大大降低代码速度。 Boost自带的序列化函数要快一些。
我现在想在写出新数据文件时始终转换为使用 Boost 版本,但仍然能够读取旧数据文件。使用旧二进制文件读取新文件不是问题。
问题是新的序列化没有版本化(很明显)。此外,我什至不知道如何尝试使用旧版本的代码读取存档并立即使用新版本再次将其写出,因为 deserialisation/serialisation 特征是全局属性。
a) 透明地读入旧文件和新文件,同时始终写入新文件,或者 b) 读入旧文件并立即以新格式写出的最佳方法是什么?
如果文件版本为"old",您可以保留旧的实现并使用它。
仅在保存或文件版本为"new"时使用复杂序列化的boost版本。
如果您有一个包含要序列化的复杂数据的对象,这应该是微不足道的,因为可以通过改变包含对象的版本来实现这一点
更新
示例,使用简单的包装器调用旧式序列化:
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/complex.hpp>
template <typename T> struct old_format_wrapper {
T& wrapped;
old_format_wrapper(T& w) : wrapped(w) {}
};
template <typename T>
old_format_wrapper<T> old_format(T& w) { return {w}; }
namespace boost { namespace serialization {
template<class Archive, typename T>
void serialize(Archive& ar, old_format_wrapper<std::complex<T> >& comp, unsigned) {
ar & reinterpret_cast<T(&)[2]>(comp.wrapped)[0];
ar & reinterpret_cast<T(&)[2]>(comp.wrapped)[1];
}
} }
struct IHaveComplexData {
std::complex<double> data;
template <typename Ar> void serialize(Ar& ar, unsigned version) {
switch(version) {
case 0: { // old
auto wrap = old_format(data);
ar & wrap;
}
break;
case 1: // new
default:
ar & data; // uses boost serialization
break;
}
}
};
int main() {
{
boost::archive::text_oarchive oa(std::cout);
IHaveComplexData o { { 2, 33 } };
oa << o;
}
{
std::istringstream iss("22 serialization::archive 13 0 0 0 0 2.00000000000000000e+00 3.30000000000000000e+01");
boost::archive::text_iarchive ia(iss);
IHaveComplexData o;
ia >> o;
std::cout << o.data;
}
}
打印(取决于您的 boost 版本):
22 serialization::archive 13 0 0 0 0 2.00000000000000000e+00 3.30000000000000000e+01
(2,33)
当然你现在可以设置BOOST_CLASS_VERSION(IHaveComplexData, 1)