C++ Boost序列化:在不破坏兼容性的情况下添加新的寄存器类型
我使用Boost用如下代码序列化一个NeuralNetwork对象C++ Boost序列化:在不破坏兼容性的情况下添加新的寄存器类型,c++,serialization,boost,boost-serialization,C++,Serialization,Boost,Boost Serialization,我使用Boost用如下代码序列化一个NeuralNetwork对象 template <class Archive> void NeuralNetwork::serialize(Archive& ar, unsigned version) { boost::serialization::void_cast_register<NeuralNetwork, StatisticAnalysis>(); ar & boost::serializat
template <class Archive>
void NeuralNetwork::serialize(Archive& ar, unsigned version)
{
boost::serialization::void_cast_register<NeuralNetwork, StatisticAnalysis>();
ar & boost::serialization::base_object<StatisticAnalysis>(*this);
ar.template register_type<FullyConnected>(); // derived from Layer object
ar.template register_type<Recurrence>();
ar.template register_type<Convolution>();
ar.template register_type<MaxPooling>();
ar & layers; // vector<unique_ptr<Layer>>
}
模板
void NeuralNetwork::序列化(存档&ar,未签名版本)
{
boost::serialization::void_cast_register();
ar&boost::serialization::base_对象(*this);
ar.template register_type();//从图层对象派生
ar.template寄存器类型();
ar.template寄存器类型();
ar.template寄存器类型();
ar&layers;//向量
}
我的问题是,我已经有对象已经序列化,当我添加了一个新的类继承自Lead,我有以下错误:<代码>未知文件:错误:C++异常与描述“未注册类”在测试主体中抛出。< /代码> < /P>
如何添加新的寄存器类型
不破坏与已序列化和已保存对象的兼容性
当我添加一个新的继承自Lead的类时,我有以下错误:未知文件:错误:C++异常与描述“未注册类”在测试体中抛出。 我认为这是由于其他原因
参考点:“自动”类型注册 典型的模式是不使用寄存器类型
。相反,您将使用自动注册机制:
- 版本1
- 版本2(
)-DVERSION2
register\u type
实际上不会产生兼容性问题-文档可能是:
请注意,如果序列化函数在save和load之间拆分,则这两个函数都必须包含注册。这是在同步中保持保存和相应加载所必需的
注意:在看到文本归档的输出与预期的相同之后,我还修改为写入二进制归档,以防其中存在一些实现差异
(v1和v2两种版本同时出现):
成功完成,写入完全相同的归档v1.bin和v2.bin,MD5总和证明了这一点:
5bba3ef7d8a25bd50d0768fed5dfed64 v1.bin
5bba3ef7d8a25bd50d0768fed5dfed64 v2.bin
总结-从这里到哪里
我认为原则上添加子类不应该破坏归档兼容性。如果是这样的话
- 从以上两个选项中寻找实现方法的差异
- 寻找其他同时发生的变化
- 使用git bisect之类的工具来检查最后一个仍然可以反序列化的“工作”版本,从而隔离破坏性的更改
- 检查例如boost库版本是否兼容
- 确保您没有使用不可移植的归档(请注意;另请参阅)
如果你遇到更多的信息,我会在这里。如果问题变得不同了,请考虑打开一个新的问题。我觉得我的代码在没有<代码> ReavestyType 的情况下是不起作用的。但是这是一段时间前,所以我将尝试删除它们并保持你的位置。在版本为“代码> ReavestyType类型< /代码> >如果行<代码> ..RealStaseRealStyType();code>放在其他两个校验和不同之前,我的问题一定来自那里。我将看到升级到第一个版本,即使它目前不工作。是的,混淆订单是不好的-文件报价确认这一部分。所以,基本上,我认为我们可以得出结论,你在列表的末尾追加是没有问题的?我仍然有问题,甚至把新的register_类型放在末尾(因为我有两个register_类型的列表)。而且没有register\u类型的版本不起作用,因为我的
BOOST\u CLASS\u EXPORT
在*.cpp中(我特别好奇的是,我们是否可以在保留旧式兼容性的同时从旧式切换到自动注册。这可能是不可能的,或者只使用类版本控制)
Data: "22 serialization::archive 17 0 0 1 13 NeuralNetwork 1 0
0 0 0 3 0 1 2 3 0 0 6 0 0 0 7 14 FullyConnected 1 0
1 1 0
2 8 10 Recurrence 1 0
3
4 9 11 Convolution 1 0
5
6 7
7
8 7
9
10 10 10 MaxPooling 1 0
11
12
"
6 layers: { FullyConnected Recurrence Convolution FullyConnected FullyConnected MaxPooling }
//#define VERSION2
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/unique_ptr.hpp>
#include <boost/serialization/access.hpp>
#include <boost/serialization/vector.hpp>
#include <fstream>
#include <iostream>
#include <iomanip>
#include <boost/core/demangle.hpp>
using boost::serialization::base_object;
using boost::core::demangle;
struct StatisticAnalysis {
virtual ~StatisticAnalysis() = default;
virtual void report(std::ostream&) const = 0;
std::vector<int> base_data {1,2,3};
void serialize(auto& ar, unsigned) { ar & base_data; }
friend std::ostream& operator<<(std::ostream& os, StatisticAnalysis const& sa) {
sa.report(os);
return os;
}
};
BOOST_SERIALIZATION_ASSUME_ABSTRACT(StatisticAnalysis)
BOOST_CLASS_EXPORT(StatisticAnalysis)
struct Layer {
virtual ~Layer() = default;
void serialize(auto&, unsigned) { }
};
BOOST_SERIALIZATION_ASSUME_ABSTRACT(Layer)
BOOST_CLASS_EXPORT(Layer)
struct FullyConnected : Layer { void serialize(auto &ar, unsigned) { ar &base_object<Layer>(*this); } };
struct Recurrence : Layer { void serialize(auto &ar, unsigned) { ar &base_object<Layer>(*this); } };
struct Convolution : Layer { void serialize(auto &ar, unsigned) { ar &base_object<Layer>(*this); } };
struct MaxPooling : Layer { void serialize(auto &ar, unsigned) { ar &base_object<Layer>(*this); } };
//BOOST_CLASS_EXPORT(FullyConnected)
//BOOST_CLASS_EXPORT(Recurrence)
//BOOST_CLASS_EXPORT(Convolution)
//BOOST_CLASS_EXPORT(MaxPooling)
#if defined(VERSION2)
struct NewLayer : Layer {
void serialize(auto &ar, unsigned) { ar &base_object<Layer>(*this); }
};
//BOOST_CLASS_EXPORT(NewLayer)
#endif
struct NeuralNetwork : StatisticAnalysis {
virtual void report(std::ostream& os) const override {
os << layers.size() << " layers: {";
for (auto& layer : layers) {
os << " " << demangle(typeid(*layer).name());
}
os << " }\n";
}
std::vector<std::unique_ptr<Layer> > layers;
void serialize(auto& ar, unsigned) {
ar &base_object<StatisticAnalysis>(*this);
ar.template register_type<FullyConnected>(); // derived from Layer object
ar.template register_type<Recurrence>();
ar.template register_type<Convolution>();
ar.template register_type<MaxPooling>();
#if defined(VERSION2)
ar.template register_type<NewLayer>();
#endif
ar &layers;
}
};
BOOST_CLASS_EXPORT(NeuralNetwork)
int main(int, char **argv) {
std::string program_name(*argv);
std::unique_ptr<StatisticAnalysis> analysis;
{
std::ofstream ofs(program_name + ".bin", std::ios::binary);
boost::archive::binary_oarchive oa(ofs);
analysis = [] {
auto nn = std::make_unique<NeuralNetwork>();
nn->layers.emplace_back(std::make_unique<FullyConnected>());
nn->layers.emplace_back( std::make_unique<Recurrence>());
nn->layers.emplace_back(std::make_unique<Convolution>());
nn->layers.emplace_back(std::make_unique<FullyConnected>());
nn->layers.emplace_back(std::make_unique<FullyConnected>());
nn->layers.emplace_back(std::make_unique<MaxPooling>());
return nn;
}();
oa << analysis;
}
{
std::ifstream ifs(program_name + ".bin", std::ios::binary);
boost::archive::binary_iarchive ia(ifs);
analysis.reset();
ia >> analysis;
std::cerr << *analysis << "\n";
}
}
g++ -std=c++20 -Os -DVERSION1 -lboost_serialization main.cpp -o v1
g++ -std=c++20 -Os -DVERSION2 -lboost_serialization main.cpp -o v2
./v1 && ./v2 && md5sum v1.bin v2.bin
5bba3ef7d8a25bd50d0768fed5dfed64 v1.bin
5bba3ef7d8a25bd50d0768fed5dfed64 v2.bin