如何在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; }
关键说明
- 自定义归档类:
CustomBinaryIArchive继承自binary_iarchive,重写load_object方法实现类型判断逻辑。 - 类型识别:通过
extended_type_info对比待读取类型与已废弃的MyType1,匹配则跳过数据并将指针置空。 - 读取处理:读取后通过指针是否为
nullptr判断是否为已丢弃的实例,避免错误解析和内存泄漏。
内容的提问来源于stack exchange,提问作者Hugal31
相关产品推荐
相关产品推荐

