Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

跨越边界使用 EnTT

目录

跨越边界工作

历史上,EnTT 在 Windows 上跨边界使用,以及在 GNU/Linux 上默认可见性 (visibility) 设置为 hidden 时跨边界使用,一直存在一个限制。该限制主要是由于一个用于为不同类型分配唯一的、顺序的标识符的自定义工具引起的。
幸运的是,如今 EnTT 可以顺畅地跨边界工作。

默认顺畅,除非另有证明

EnTT 中的许多类为了其目的广泛使用了类型擦除 (type erasure)。这引发了识别类型已被擦除的对象的需求。
type_hash 类模板是生成标识符并使其可供库的其余部分使用的方式。通常,这个类很少引起关注。唯一的例外是当标识符之间发生冲突时(尽管这绝对不常见),或者当 EnTT 提供的默认解决方案不适合用户的目的时。
专门介绍 type_info 的部分包含了以简洁优雅的方式解决该问题的所有详细信息。请参阅特定文档。

在使用链接库 (linked libraries) 时,编译定义 ENTT_API_EXPORTENTT_API_IMPORT 用于导入或导出符号,从而使一切都能良好地跨边界工作。
另一方面,当使用不导出任何符号的插件 (plugins) 或共享库 (shared libraries) 时,一切也应该顺畅运行。

对于需要更多详细信息的人,测试套件包含许多涵盖最常见情况的示例(有关所有详细信息,请参阅 lib 目录)。
不言而喻,不可能涵盖 所有 可能的情况。然而,所提供的示例有望作为所有情况的基础。

Meta context

在跨边界使用时,运行时反射系统 (runtime reflection system) 值得特别一提。
由于它已经链接到元素所附加的静态 context,并且不同的 context 彼此不相关,因此必须 共享 (share) 它们以允许跨边界使用 meta types。

幸运的是,共享 context 也非常简单。首先,在主空间 (main space) 中获取本地 context:

auto handle = entt::locator<entt::meta_ctx>::handle();

然后,将其传递给接收空间 (receiving space),接收空间将其设置为默认 context,从而丢弃或搁置本地 context:

entt::locator<entt::meta_ctx>::reset(handle);

从现在起,两个空间都引用同一个 context,并且所有新的 meta types 都附加到它,无论它们在哪里创建。
请注意,替换 (replacing) 主 context 也不会将更改传播到边界之外。换句话说,替换 context 会导致两侧解耦 (decoupling),从而导致内容出现分歧。

内存管理

由于内存管理,还存在另一个可能导致令人头疼的微妙问题。
它可能发生在按需动态创建对象池(例如 components 或 events)的地方。当使用依赖相同动态运行时 (dynamic runtime) 的链接库时,这通常不是问题。然而,在插件 (plugins) 或静态链接运行时 (statically linked runtimes) 的情况下,它可能会发生。

例如,想象在主可执行文件 (main executable) 中创建一个 registry 实例并将其与插件共享。如果后者开始使用前者未知的 component,则在首次使用时会在 registry 内创建一个专用池。
可以猜到,这个池是在与 registry 不同的边界另一侧实例化的。因此,该实例现在正在管理来自不同空间的内存,如果处理不当,这可能很快导致崩溃。

为了克服这种风险,建议使用定义良好的接口,使基本类型 (fundamental types) 穿过边界,适时且适当地隔离 EnTT 类的实例。
请参阅测试套件中的一些示例,阅读在线提供的有关此类问题的文档,或咨询已有此类经验的人以避免出现问题。