从 DLL 调用谷物档案导致多态性不起作用

问题描述 投票:0回答:1

我是麦片的新手,最近我遇到了一个奇怪的问题, 我的序列化代码位于外部 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;
}
c++ dll polymorphism cereal
1个回答
0
投票

问题在于,当

IndirectCaller.cpp
位于 dll 中时,您在序列化时没有派生类的多态注册代码。

当您调用

CEREAL_REGISTER_TYPE(T)
时,谷物正在做什么,它会创建一堆全局
StaticObject<>
实例,这些实例向所有注册/包含的档案注册该类型。如果您有动态库,这些全局对象不会在 dll 和可执行文件之间共享 - 每个对象都有自己的一组已注册多态对象。

您需要在所有存档和所有类型都已注册的上下文中执行序列化。如果您在动态库中注册基类,并在可执行文件中注册派生类,这意味着必须直接从可执行文件调用

Archiver
代码。

© www.soinside.com 2019 - 2024. All rights reserved.