C++ Boost序列化:在不破坏兼容性的情况下添加新的寄存器类型

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

我使用Boost用如下代码序列化一个NeuralNetwork对象

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