You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在boost::serialize中忽略已废弃类以兼容旧序列化文件

问题描述

使用Boost序列化库时,通过register_type注册待序列化的类。当某个类(如示例中的MyType1)不再使用后,读取包含该类实例的旧序列化文件时,希望直接丢弃该类的实例,但当前实现会出现错误(比如错误地将MyType1的数据解析为MyType2实例),需要解决这个问题。

解决方案

要实现读取时丢弃已废弃类的实例,核心是让归档能够识别未知类型,并跳过对应的数据块。以下是可行的实现方案:

自定义归档处理未知类型

通过继承Boost的归档类,重写load_object方法,在读取对象前判断类型,若为已废弃的类则跳过对应数据,避免错误解析。

修改后的示例代码

#include <iostream>
#include <sstream>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/serialization/extended_type_info.hpp>

struct Base
{
    virtual ~Base() = default;

    template <class Archive>
    void serialize(Archive &ar, long int version)
    {}

    virtual void display(std::ostream &os) const = 0;
};

struct MyType1 : public Base
{
    int i, j;

    MyType1(): MyType1(0, 0) {}
    MyType1(int i_, int j_): i {i_}, j {j_} {}
    ~MyType1() override = default;

    template <class Archive>
    void serialize(Archive &ar, long int version)
    {
        ar & boost::serialization::base_object<Base>(*this);
        ar & i;
        ar & j;
    }

    void display(std::ostream &os) const override
    {
        os << "MyType1{" << i << ", " << j << "}";
    }
};

struct MyType2 : public Base
{
    float a;

    MyType2(): MyType2(0.f) {}
    MyType2(float a_): a {a_} {}
    ~MyType2() override = default;

    template <class Archive>
    void serialize(Archive &ar, long int version)
    {
        ar & boost::serialization::base_object<Base>(*this);
        ar & a;
    }

    void display(std::ostream &os) const override
    {
        os << "MyType2{" << a << '}';
    }
};

std::ostream &operator<<(std::ostream &os, Base const &b)
{
    b.display(os);
    return os;
}

// 自定义输入归档,处理已废弃类型
class CustomBinaryIArchive : public boost::archive::binary_iarchive {
public:
    using boost::archive::binary_iarchive::binary_iarchive;

protected:
    template<class T>
    void load_object(T * &t) {
        // 获取当前待读取的类型信息
        const boost::serialization::extended_type_info *eti = this->get_next_etype();
        if (!eti) {
            boost::archive::binary_iarchive::load_object(t);
            return;
        }

        // 判断是否为已废弃的MyType1
        if (*eti == *boost::serialization::extended_type_info_typeid<MyType1>()) {
            // 跳过该对象的数据块
            this->next_object_pointer(nullptr);
            boost::archive::binary_iarchive::load_object(t);
            t = nullptr; // 标记该实例已丢弃
        } else {
            // 正常处理已知类型
            boost::archive::binary_iarchive::load_object(t);
        }
    }
};

int main()
{
    std::stringstream stream;

    {
        boost::archive::binary_oarchive oar {stream};
        oar.register_type<MyType1>();
        oar.register_type<MyType2>();
        Base *foo1 = new MyType1 {42, 12},
                *foo2 = new MyType2 {32.f};

        oar << foo1 << foo2;
        delete foo1;
        delete foo2;
    }

    CustomBinaryIArchive iar {stream};
    
    iar.register_type<MyType2>();
    Base *obj = nullptr;
    
    // 读取第一个对象(MyType1,会被丢弃)
    iar >> obj;
    if (obj) {
        std::cout << *obj << '\n';
        delete obj;
    } else {
        std::cout << "已丢弃MyType1实例\n";
    }

    // 读取第二个对象(MyType2,正常解析)
    iar >> obj;
    if (obj) {
        std::cout << *obj << '\n';
        delete obj;
    }

    return 0;
}

关键说明

  1. 自定义归档类:CustomBinaryIArchive继承自binary_iarchive,重写load_object方法实现类型判断逻辑。
  2. 类型识别:通过extended_type_info对比待读取类型与已废弃的MyType1,匹配则跳过数据并将指针置空。
  3. 读取处理:读取后通过指针是否为nullptr判断是否为已丢弃的实例,避免错误解析和内存泄漏。

内容的提问来源于stack exchange,提问作者Hugal31

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 13:30:41