Boost序列化含多态类指针的Container类失败问题排查
问题分析:Boost多态成员指针序列化失败的根源及修复
你的代码存在三个核心问题,导致多态指针的序列化/反序列化无法正确识别子类:
1. 对象切片:拷贝构造函数的错误实现
Container的拷贝构造函数中,std::make_unique<Parent>((*container.m_parent))直接将子类对象(ChildA)切片为基类对象(Parent)——解引用container.m_parent得到的是Parent类型的引用,用它构造Parent实例时,子类特有的数据(m_value)会被丢弃,最终vector中存储的Container实例的m_parent指向的是一个空的Parent对象,而非原有的ChildA对象。这是序列化后数据为空的直接原因。
2. register_type调用位置错误
在ChildA的serialize函数中调用ar.template register_type<ChildA>()是冗余且不符合规范的。Boost序列化要求基类的序列化函数中注册子类类型,或者在使用归档对象前全局注册,这样归档才能在序列化多态指针时识别子类类型。
3. 缺少多态拷贝的支持
由于Parent是抽象基类,直接拷贝会触发切片,必须为基类添加纯虚的克隆方法,让子类实现自身的拷贝逻辑,保证拷贝时能正确生成子类实例。
修复后的关键代码片段
1. 给Parent添加纯虚clone方法
class Parent { public: Parent(); virtual ~Parent() = default; virtual std::string print() const; // 添加多态克隆方法 virtual std::unique_ptr<Parent> clone() const = 0; friend std::ostream& operator<<(std::ostream& out, const Parent& Parent); friend class boost::serialization::access; template<class Archive> void serialize(Archive& ar, const unsigned int version) { // 在基类序列化函数中注册子类 ar.template register_type<ChildA>(); } };
2. ChildA实现clone方法并修正serialize函数
class ChildA : public Parent { private: double m_value; public: ChildA() {}; ChildA(double value); std::string print() const override; // 实现克隆方法 std::unique_ptr<Parent> clone() const override { return std::make_unique<ChildA>(*this); } friend class boost::serialization::access; template<class Archive> void serialize(Archive& ar, const unsigned int version) { // 移除多余的register_type调用 ar & boost::serialization::base_object<Parent>(*this); ar & m_value; } };
3. 修正Container的拷贝构造函数
Container::Container(const Container& container): m_id(container.m_id) { // 使用克隆方法实现多态拷贝,避免切片 if (container.m_parent) { m_parent = container.m_parent->clone(); } }
修复后效果
- 拷贝Container时,m_parent会正确复制ChildA实例,不会发生切片
- 序列化时,归档能识别多态指针指向的子类类型,完整序列化ChildA的m_value
- 反序列化后,m_parent会重新指向ChildA实例,输出结果为
1,2.300000而非空值
内容的提问来源于stack exchange,提问作者Hina
相关产品推荐
相关产品推荐

