设计模式——在c++中,当实现(一组单例)直接从它们的编译单元在某个注册表中自注册时,它被称为什么?

design patterns - What is it called when implementations (of a group of singletons) self-register in some registry directly from their compilation unit in C++?

本文关键字:单元 注册表 为什么 编译 注册 实现 c++ 一组 单例 设计模式      更新时间:2023-10-16

假设我们有这样的方案:

qqqapi.h:

int register_qqq(Qqq* klass);

qqqalpha.cpp:

QqqAlpha::QqqAlpha(...) : Qqq(...) { }
QqqAlpha instance;
int dummy = register_qqq(&instance);

qqqbeta.cpp:

QqqBeta::QqqBeta(...) : Qqq(...) { }
QqqBeta instance;
int dummy = register_qqq(&instance);

通过这种方式,您可以通过复制源文件和头文件,更改适当的标识符来创建新的qqq类型。不需要手动添加任何东西到任何列表

这个模式怎么叫?对于如何正确地实施这些事情,有什么建议吗?

这个方案的一个主要问题是c++实现处理整个翻译单元

考虑一个包含数百个翻译单元的静态库。就编译器和链接器所知,您的程序只使用了一两个。他们几乎不知道,通过在注册表对象中自动注册的方式,您的程序实际上使用了五个单元!

因此,链接器删除了库提供的所有翻译单元,除了代码直接使用的一两个翻译单元,例如通过调用函数或引用变量。

结果:神秘的运行时失败,其中单例注册表不包含它应该包含的内容。

这可能是模式/习语/whatchammacallit很少使用的原因。它适用于目标代码文件,因为这样你就显式地告诉链接器要包含什么。对于静态库,它的效果就不那么好了。


最佳实践是确保,最好通过代码,但可能通过文档,从翻译单元调用或引用的东西,例如由main

这确保了有一个可见的依赖,这样翻译单元就不会被移除。

我不知道它有什么常用的名称。在过去,在另一种语言中,有一种叫做模块信封的东西,您可以将其视为负责模块初始化和清理的静态对象的构造函数和析构函数的执行。但是c++不支持这一点,而且据我回忆,最近几年在谷歌上搜索这个术语并没有提供任何相关的结果;就像所有关于它的信息都消失了…