我是麦片的新手,最近我遇到了一个奇怪的问题, 我的序列化代码位于外部 DLL 中,在代码中我使用谷物的多态性功能,当尝试从可执行文件调用 DLL 中的 archive() 方法时,程序崩溃,但是只有当 archive() 时才会发生这种情况方法是从编译的代码中调用的(我怀疑),如果它对调用者可见(由主函数直接调用),则不会崩溃, 另外,如果我禁用多态使用,则不会发生崩溃, 另外,如果我将 DLL 更改为静态库,也不会崩溃。
崩溃是由 UNREGISTERED_POLYMORPHIC_EXCEPTION 引起的。它指定我需要注册多态类型,尽管我提前注册了它,但它似乎不存在于绑定映射中。
我设计了一个小例子来演示这个问题: 我使用的是 Windows 10 MSVC 2022 麦片 v1.3.2
在外部DLL中
存档器.hpp
#pragma once
#include <cereal/archives/xml.hpp>
#include <cereal/types/polymorphic.hpp>
#include <cereal/types/vector.hpp>
#include <iostream>
#include <fstream>
#include "myclasses.hpp"
class __declspec(dllexport) Archiver
{
public:
void add(std::shared_ptr<BaseClass> cls)
{
classes.push_back(cls);
}
void save()
{
std::ofstream os("polymorphism_test.xml");
cereal::XMLOutputArchive oarchive(os);
oarchive(classes);
}
void load()
{
{
std::ifstream is("polymorphism_test.xml");
cereal::XMLInputArchive iarchive(is);
std::vector<std::shared_ptr<BaseClass>> ptrs;
iarchive(ptrs);
//ptrs[0]->sayType();
ptrs[0]->sayType();
}
}
std::vector<std::shared_ptr<BaseClass>> classes;
};
IndirectCaller.hpp
#pragma once
struct BaseClass;
#include <memory>
class __declspec(dllexport) indirectCaller
{
public:
void call(std::shared_ptr<BaseClass> cls);
};
IndirectCaller.cpp
#include "indirectCaller.hpp"
#include "archiver.hpp"
void indirectCaller::call(std::shared_ptr<BaseClass> cls)
{
Archiver a;
a.add(cls);
a.save();
a.load();
}
我的类.hpp
#pragma once
// Include the polymorphic serialization and registration mechanisms
#include <cereal/types/polymorphic.hpp>
// A pure virtual base class
struct BaseClass
{
virtual void sayType() = 0;
};
在可执行文件中
NewDerived.hpp
#pragma once
// Include the polymorphic serialization and registration mechanisms
#include <cereal/types/polymorphic.hpp>
#include "myclasses.hpp"
// A class derived from BaseClass
struct DerivedClassThree : public BaseClass
{
void sayType()
{
std::cout << "Derived 3" << std::endl;
}
int x;
template<class Archive>
void serialize(Archive& ar)
{
ar(x);
}
};
#include <cereal/archives/binary.hpp>
#include <cereal/archives/xml.hpp>
#include <cereal/archives/json.hpp>
CEREAL_REGISTER_TYPE(DerivedClassThree);
CEREAL_REGISTER_POLYMORPHIC_RELATION(BaseClass, DerivedClassThree)
主.cpp
#include "myclasses.hpp"
#include <cereal/archives/xml.hpp>
#include <cereal/types/polymorphic.hpp>
#include <iostream>
#include <fstream>
#include "newderived.hpp"
#include "indirectCaller.hpp"
int main()
{
indirectCaller a;
a.call(std::make_shared<DerivedClassThree>());
return 0;
}
问题在于,当
IndirectCaller.cpp
位于 dll 中时,您在序列化时没有派生类的多态注册代码。
当您调用
CEREAL_REGISTER_TYPE(T)
时,谷物正在做什么,它会创建一堆全局 StaticObject<>
实例,这些实例向所有注册/包含的档案注册该类型。如果您有动态库,这些全局对象不会在 dll 和可执行文件之间共享 - 每个对象都有自己的一组已注册多态对象。
您需要在所有存档和所有类型都已注册的上下文中执行序列化。如果您在动态库中注册基类,并在可执行文件中注册派生类,这意味着必须直接从可执行文件调用
Archiver
代码。