C++单身人士:这个解决方案有多好?优点/缺点,替代方案

Cor*_*uzu 4 c++ singleton design-patterns

我正在开发一个C++项目,它有多个必须是单例的类,它们之间存在依赖关系(初始化顺序很重要).

我想出了这个解决方案:

  1. 我想成为单身人士的所有类都有受保护的构造函数,例如:
class MySingleton1
{
protected:
    MySingleton1();
}
Run Code Online (Sandbox Code Playgroud)
  1. 有一个源文件singleton_factory.cpp包含一个实例化的类Singletons,它派生自我想成为单例的所有类,如下所示:
#include "MySingleton1.hpp"
#include "MySingleton2.hpp"

class Singletons : public MySingleton1, public MySingleton2 {}
static Singletons s_singletons;
Run Code Online (Sandbox Code Playgroud)
  1. 仍然在singleton_factory.cpp中,对于每个单例类型,还实现了getSingleton函数的化:
template<>
MySingleton1& getSingleton()
{
    return s_singletons;
}

template<>
MySingleton2& getSingleton()
{
    return s_singletons;
}
Run Code Online (Sandbox Code Playgroud)
  1. 的特getSingleton将是"藏"的通用模板变形下,在singleton_factory.hpp:
template <class TSingleton>
TSingleton& getSingleton();
Run Code Online (Sandbox Code Playgroud)

好处:

  • 低耦合:

    • Singleton类不需要"知道"Singletons类,唯一需要在受保护的限定符下隐藏它们的构造函数(这甚至不是强制性的,只是好的做法).实际上知道Singletons类的唯一代码是singleton_factory.cpp
    • 具体实例的瘦依赖:想要使用类型T的单例的代码只需要包含类型为T的头和skinny singleton_factory.hpp
  • 可以通过改变 Singletons类的继承顺序来控制初始化顺序

  • 没有延迟初始化 => 线程安全
  • getSingleton()很快,没有dynamic_cast,没有reinterpret_cast

缺点:

  • 每次出现一个新的单例类型时,必须将一个getSingleton特化,即" return s_singletons; "添加到singleton_factory.cpp中

所以,据我所知,这实际上是相当不错的,所以我想这样离开它,但我要求你的反馈(比编程社区更好的地方呢?).

您对此解决方案有什么额外的优势/劣势

你有什么选择吗?

Yak*_*ont 6

这迫使Singletons集中化,这可能会破坏更复杂项目中的依赖关系.singleton.cpp必须依赖于每个单身人士所需的一切的图书馆.同时,使用单身人士的任何人都必须依赖于singleton.cpp图书馆.

基本上,您的代码只能在单片非模块化项目中工作.将其扩展到多个动态库几乎是不可能的.

您的初始化顺序必须手动维护.

静态全局变量的构造点在第一个表达式之前的所有内容都没有排序main.


我用过的一个不错的解决方案是创建一个包含单例内存的动态库.

要成为单例,您从CRTP助手继承,它提供::Instance()内联方法.人们想要使用单身人士::Instance().

::Instance()创建静态局部变量生命周期令牌.然后它尝试从主DLL获取单例的存储空间; 如果已经创建了对象,它只是将存储转换为对象类型,并增加其引用计数.

如果没有,它会创建新存储并在其中构造对象.

在破坏静态局部变量生命周期令牌时,它会减少引用计数.如果该引用计数达到0,则会在当前动态库中本地销毁它.

单例的生命周期现在是::Instance()创建变量的生命周期的并集.破坏发生在非类型擦除的代码中,因此我们不必担心卸载代码的DLL.存储是核心.存储存储的DLL必须低于Singleton系统的每个用户,但它反过来没有依赖关系,所以这不是一个痛苦.

这远非完美; 单身人士和一生都是一个长期存在的问题,因为单身人士的存在使得干净的程序关闭变得困难并且变得更加困难.但它迄今为止在一个相当大的项目中工作.

  • "清洁程序关闭很难,单身人士的存在变得更加困难"来自C++福音第98章第18节.它们是问题的一个持续来源,部分原因是很难为静态de-init问题编写可靠的单元测试. (3认同)