为什么 boost::serialize 不起作用,尽管一切看起来都正确?( "unregistered class" )
Why does boost::serialize not work despite everything seeming right? ("unregistered class")
我对此感到疑惑。我有一个C++程序,它包含许多从公共根派生的数据结构,我需要使用Boost对它们进行序列化。每一个都有一个内联成员函数来接受访问者(这样我就可以在没有"switch"语句的情况下访问该结构)。
对象看起来像这样:
在.h文件中:
// Graphic component.
struct GraphicComponent : public Component {
... data members ...
void accept(ComponentVisitor &vis) { vis.visitGraphicComponent(*this); }
private:
// Serialization routine.
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive &a, const unsigned int v);
};
BOOST_CLASS_EXPORT_KEY(GraphicComponent)
// Position component.
struct PositionComponent : public Component {
... data members ...
void accept(ComponentVisitor &vis) { vis.visitPositionComponent(*this); }
private:
// Serialization routine.
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive &a, const unsigned int v);
};
BOOST_CLASS_EXPORT_KEY(PositionComponent)
...
在.cpp文件中,我声明了"serialize"例程:
BOOST_CLASS_EXPORT_IMPLEMENT(GraphicComponent)
BOOST_CLASS_EXPORT_IMPLEMENT(PositionComponent)
...
template<class Archive>
void GraphicComponent::serialize(Archive &a, const unsigned int v)
{
a & boost::serialization::base_object<Component>(*this);
... serialize data members ...
}
template<class Archive>
void PositionComponent::serialize(Archive &a, const unsigned int v)
{
a & boost::serialization::base_object<Component>(*this);
... serialize data members ...
}
...
我还通过一个公共头包含了Boost存档。据我所知,一切看起来都很好。在基本组件上还有一个"BOOST_RIALIZATION_ASSUME_ABSTRACT",因为"accept"是纯虚拟的。
当我运行程序并将其序列化时,我得到了
what(): unregistered class - derived class not registered or exported
序列化通过指向基本组件的指针进行。
我听说过有关Boost序列化和"库"的问题。我使用的构建系统CMake是通过将程序的子组件组装到库中,然后将这些子组件组合成一个可执行文件来编译程序的。这可能是问题所在吗?
此外,Component派生自std::enable_shared_from_this(这是C++11 STL,而不是Boost)——这可能是问题所在吗?如果是这样,该怎么办?
如果它有帮助,这里有一个工作的SSCCE(或评论所说的MCVE):
在Coliru上直播
#include <boost/serialization/access.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
struct ComponentVisitor;
struct Component {
virtual ~Component() = default;
virtual void accept(ComponentVisitor &v) = 0;
private:
// Serialization routine.
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive &, const unsigned int) {}
};
BOOST_SERIALIZATION_ASSUME_ABSTRACT(Component)
struct GraphicComponent;
struct PositionComponent;
struct ComponentVisitor {
virtual void visitGraphicComponent(GraphicComponent const &){};
virtual void visitPositionComponent(PositionComponent const &){};
};
// Graphic component.
struct GraphicComponent : public Component {
void accept(ComponentVisitor &vis) { vis.visitGraphicComponent(*this); }
private:
// Serialization routine.
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive &a, const unsigned int v);
};
BOOST_CLASS_EXPORT_KEY(GraphicComponent)
// Position component.
struct PositionComponent : public Component {
void accept(ComponentVisitor &vis) { vis.visitPositionComponent(*this); }
private:
// Serialization routine.
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive &a, const unsigned int v);
};
BOOST_CLASS_EXPORT_KEY(PositionComponent)
/////////////////////////////////////////////////////
BOOST_CLASS_EXPORT_IMPLEMENT(GraphicComponent)
BOOST_CLASS_EXPORT_IMPLEMENT(PositionComponent)
//...
template <class Archive>
void GraphicComponent::serialize(Archive &a, const unsigned int)
{
a &boost::serialization::base_object<Component>(*this);
//... serialize data members ...
}
template <class Archive>
void PositionComponent::serialize(Archive &a, const unsigned int)
{
a &boost::serialization::base_object<Component>(*this);
//... serialize data members ...
}
#include <boost/make_shared.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/vector.hpp>
#include <sstream>
int main() {
std::stringstream ss;
{
std::vector<boost::shared_ptr<Component> > components {
boost::make_shared<GraphicComponent>(),
boost::make_shared<PositionComponent>(),
boost::make_shared<PositionComponent>(),
boost::make_shared<GraphicComponent>(),
};
boost::archive::text_oarchive oa(ss);
oa << components;
}
{
std::vector<boost::shared_ptr<Component> > deserialized;
boost::archive::text_iarchive ia(ss);
ia >> deserialized;
struct printer : ComponentVisitor {
void visitPositionComponent(PositionComponent const & /*pc*/){ std::cout << __PRETTY_FUNCTION__ << "n"; }
void visitGraphicComponent(GraphicComponent const & /*gc*/){ std::cout << __PRETTY_FUNCTION__ << "n"; }
} print;
for (auto c : deserialized)
c->accept(print);
}
}
打印
virtual void main()::printer::visitGraphicComponent(const GraphicComponent&)
virtual void main()::printer::visitPositionComponent(const PositionComponent&)
virtual void main()::printer::visitPositionComponent(const PositionComponent&)
virtual void main()::printer::visitGraphicComponent(const GraphicComponent&)
如预期
备注
实际上,由于您只在特定的TU中使用序列化,因此可以考虑使用非侵入式序列化:
在Coliru上直播
struct ComponentVisitor; struct Component { virtual ~Component() = default; virtual void accept(ComponentVisitor &v) = 0; }; struct GraphicComponent; struct PositionComponent; struct ComponentVisitor { virtual void visitGraphicComponent(GraphicComponent const &){}; virtual void visitPositionComponent(PositionComponent const &){}; }; struct GraphicComponent : public Component { void accept(ComponentVisitor &vis) { vis.visitGraphicComponent(*this); } }; struct PositionComponent : public Component { void accept(ComponentVisitor &vis) { vis.visitPositionComponent(*this); } }; ///////////////////////////////////////////////////// // in the CPP #include <boost/serialization/access.hpp> #include <boost/serialization/export.hpp> #include <boost/serialization/base_object.hpp> #include <boost/archive/text_iarchive.hpp> #include <boost/archive/text_oarchive.hpp> BOOST_SERIALIZATION_ASSUME_ABSTRACT(Component) BOOST_CLASS_EXPORT(GraphicComponent) BOOST_CLASS_EXPORT(PositionComponent) namespace boost { namespace serialization { template <class Archive> void serialize(Archive &, Component&, const unsigned int) {} template <class Archive> void serialize(Archive &a, GraphicComponent& obj, const unsigned int) { a &boost::serialization::base_object<Component>(obj); } template <class Archive> void serialize(Archive &a, PositionComponent& obj, const unsigned int) { a &boost::serialization::base_object<Component>(obj); } } }
哪个更干净
如果您仍然想从
serialize
内部访问私人会员,请参阅例如- 获取非侵入性boost序列化的专用数据成员C++
这是一个部分答案,因为它没有确切解释它失败的原因。我已经设法解决了这个问题,把程序编译成一个单独的程序,而不是一堆静态链接在一起的库,这就是我认为我必须用我正在使用的构建系统来完成的方式,因为该系统的在线文档很简洁,当我把makefile放在一起时,我不知道该怎么做。我怀疑这与Boost在处理库中的此类代码时遇到的问题有关。
您需要在库代码中包含归档类标头。https://www.boost.org/doc/libs/1_75_0/libs/serialization/doc/special.html#export
除非还包含归档类头,否则在库代码中放置BOOST_CLASS_EXPORT将无效。因此,在构建库时,应该包括他预期使用的所有归档类的所有头。
- 这个语法std::class<>{}(arg1, arg2) 在C++中是什么意思?
- C++核心准则 C35 对于接口类"A base class destructor should be either public and virtual, or protected and nonv
- 使用模板进行堆栈实现; "name followed by :: must be a class or namespace"
- "Undefined class"作为is_base_of的论据
- 如何将class.cpp和class.hpp编译为一个.o文件
- '{'标记之前的预期类名,然后在预声明时无效使用不完整的类型'class class_name'
- 如何使用"derived input class"创建派生类?
- 错误:"Left of getValue must have class/struct/union"
- ' class a : b ' 和 ' class a : public b ' 之间的继承类不同
- Pybind11 Class Definition
- 当结构位于单独的头文件中时'unregistered datatype'在 QML 中出现Q_GADGET错误
- 在C++中使用没有合作伙伴Class/Cpp文件的头文件是否实用
- C2011 'CMemDC':Visual Studio 2019中的'class'类型重新定义
- TypeError: [c++ addon class] 不是构造函数
- C++ class template
- 当初始值设定项是基类名时'initializer does not name a non-static data member or base class'错误
- Clearing Class Foo with new(pFoo) Foo()
- C++ class vs a library
- 继承类时"invalid use of incomplete type ‘class tree_node_t’"
- 为什么 boost::serialize 不起作用,尽管一切看起来都正确?( "unregistered class" )