Boost多态序列化已注册类仍报“未注册类”错误求助
解决Boost多态序列化静态库注册失败问题
问题核心
静态库编译场景下,Boost序列化的多态类注册代码会被链接器优化丢弃,导致运行时抛出unregistered class - derived class not registered or exported错误;而共享库场景下因符号默认导出,注册代码可正常执行。
解决方案步骤
1. 标记抽象基类并分离导出声明与实现
Boost序列化要求抽象基类显式声明,同时将导出逻辑拆分为头文件声明和cpp文件实现,避免头文件重复包含问题,同时确保注册代码被正确生成。
修改base.hpp
#pragma once #include <boost/archive/text_oarchive.hpp> #include <boost/archive/text_iarchive.hpp> #include <boost/serialization/shared_ptr.hpp> #include <boost/serialization/base_object.hpp> #include <boost/serialization/export.hpp> struct Base { virtual ~Base() = default; template <class Archive> void serialize(Archive & ar, unsigned /*version*/) { ar & base_value; } int base_value; }; // 标记基类为抽象类,告知序列化系统无需实例化基类 BOOST_SERIALIZATION_ASSUME_ABSTRACT(Base) // 在头文件声明类的导出 BOOST_CLASS_EXPORT_KEY(Base)
修改base.cpp
#include "base.hpp" // 在cpp文件实现基类的导出注册 BOOST_CLASS_EXPORT_IMPLEMENT(Base)
修改derived.hpp
#include "base.hpp" struct Derived : public Base { template <class Archive> void serialize(Archive & ar, unsigned /*version*/) { ar & boost::serialization::base_object<Base>(*this); ar & derived_value; } int derived_value; }; // 在头文件声明派生类的导出 BOOST_CLASS_EXPORT_KEY(Derived)
修改derived.cpp
#include "derived.hpp" // 在cpp文件实现派生类的导出注册 BOOST_CLASS_EXPORT_IMPLEMENT(Derived)
2. 强制静态库所有对象被链接
静态库默认只会包含主程序直接引用的符号,而Boost的序列化注册依赖全局对象的构造函数(无直接引用),会被链接器优化丢弃。需通过链接器选项强制包含静态库所有对象。
修改测试程序的CMakeLists.txt
针对GCC/Clang编译器:
target_link_libraries(${mytest} PRIVATE # 仅当库为静态时,启用whole-archive选项 $<$<STATIC:${CMAKE_PROJECT_NAME}_lib>:-Wl,--whole-archive> ${CMAKE_PROJECT_NAME}_lib $<$<STATIC:${CMAKE_PROJECT_NAME}_lib>:-Wl,--no-whole-archive> gtest )
针对MSVC编译器:
target_link_options(${mytest} PRIVATE $<$<AND:$<CXX_COMPILER_ID:MSVC>,$<STATIC:${CMAKE_PROJECT_NAME}_lib>>:/WHOLEARCHIVE:${CMAKE_PROJECT_NAME}_lib> )
原理说明
- 抽象类标记:
BOOST_SERIALIZATION_ASSUME_ABSTRACT告诉Boost序列化系统基类是抽象的,无需为其生成实例化逻辑,避免多态处理时的错误检查。 - 分离导出宏:
BOOST_CLASS_EXPORT_KEY仅在头文件声明导出信息,BOOST_CLASS_EXPORT_IMPLEMENT在cpp文件生成注册全局对象,既解决头文件重复包含问题,又确保注册代码仅生成一次。 - 强制链接选项:
--whole-archive(GCC/Clang)或/WHOLEARCHIVE(MSVC)强制链接器包含静态库所有对象文件,保证注册用的全局构造函数被执行,完成类的序列化注册。
内容的提问来源于stack exchange,提问作者Elyas
相关产品推荐
相关产品推荐

