1

对于我目前正在开发的 C++ 库,我已经看到了基于共享库的插件系统的优势。只要在初始化时扫描的目录中的一个共享库提供该功能,库的用户就可以使用该功能。

使用 dlopen,将在共享库中搜索两个符号:一个函数返回命名它们实现的特性的字符串,以及一个创建函数,它实例化类并返回指向 basse 类的指针。像这样的东西:

在图书馆 A

#include "Instance.hpp"
extern "C" const char* type() {
  return "InstanceA";
}
//... class InstanceA definition, inherits from Instance
extern "C" Instance* create() {
    return new InstanceA();
}

Core 库将扫描插件目录并保留映射字符串->pointerToCreateFunction 以创建新实例。

这真的很方便,而且是一件非常标准的事情。如果用户代码尝试实例化 InstanceX 但没有共享库实现该类型,则会给出错误,一切都会正常运行。

但是这个框架也将用于 iOs 开发,并且 App Store 不允许加载 3rd 方共享对象。即使在加载静态链接插件的库的自包含版本时,我也想保留这种模块化插件结构。请注意,在项目管理级别,这就像在 CMake 中定义一个变量一样简单,该变量创建插件的静态版本并静态链接它们。这也将排除代码的动态加载部分。

我缺少的是如何反转机制:虽然对于共享对象,核心库将利用文件系统来了解可以使用的可能实例类型,但我不知道如何在不更改的情况下“注册”它们大部分代码,并且没有进入静态初始化惨败。看起来唯一的方法是通过包含所有可能的标题并有一个大的开关来替换扫描类型和创建函数的代码

Instance* theInstance;
if (instanceRequired == "instanceA") 
  theInstance = new InstanceA();
etc etc...

你有什么想法可以避免在每次添加新实例时包含所有标头并且必须更改 Core 中的代码?

4

1 回答 1

0

我通过那些在 ctor 中调用 register 的讨厌的静态对象来做这些事情。

通过使地图本身成为本地静态地图来避免排序问题,因此无论它来自哪里,都可以在第一次客户端调用时构建。(通过将线程启动限制在直到主时间来避免线程和类似问题,到那时所有重要的事情都被强制执行。)


class RegMap;  // the registry
RegMap& GetRegistry(); // the singleton access function; you can make a separate const/nonconst version or provide another wrapper for registering

//    implementation in core.cpp:
RegMap& GetRegistry()
{ 
    static RegMap m;
    return m;
}

//in client ctor:
GetRegistry().Register( key, func);
于 2013-06-27T11:17:49.893 回答