C ++ Singletons:这个解决方案有多好?优点/缺点,替代品

时间:2018-12-14 16:29:57

标签: c++ design-patterns singleton

我正在研究一个C ++项目,该项目具有多个必须为单例的类,它们之间具有依赖性(初始化的顺序很重要)。

我想出了这个解决方案:

  1. 我希望成为单例的所有类均具有受受保护的构造函数,例如:
class MySingleton1
{
protected:
    MySingleton1();
}
  1. 具有一个源文件 singleton_factory.cpp ,其中包含实例化的类 Singletons ,该类来自我想成为单例的所有类,就像这样:
#include "MySingleton1.hpp"
#include "MySingleton2.hpp"

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

template<>
MySingleton2& getSingleton()
{
    return s_singletons;
}
  1. getSingleton 的专长将被隐藏在 singleton_factory.hpp 中的通用模板变体下:
template <class TSingleton>
TSingleton& getSingleton();

优势:

  • 低耦合

    • Singleton类不需要“意识到” Singletons类,只需要将其构造函数隐藏在受保护的限定符下(这不是强制性的,只是一种好习惯)。真正了解Singletons类的唯一代码是 singleton_factory.cpp
    • 具体实例的紧迫依赖项:想要使用类型为T 的单例的代码只需包含类型为T 的标头和紧致的 singleton_factory。 hpp
  • 初始化顺序可以通过更改Singletons类的继承顺序来控制

  • 没有延迟初始化 => 线程安全吗?
  • getSingleton()快速,无动态播报,无重新解释播报

缺点:

  • 每次出现新的单例类型时,都会执行 getSingleton 专业化,即-必须将<< strong> return s_singletons; ”添加到 singleton_factory.cpp < / strong>

据我所知,这实际上还算不错,因此我想保留这种方式,但我寻求您的反馈 (这样做比编程社区哪个地方更好?)。

您看到此解决方案有哪些其他优点/缺点

您建议什么替代品

2 个答案:

答案 0 :(得分:6)

这迫使Singletons集中化,这可能使更复杂项目中的依赖关系混乱。拥有singleton.cpp的库必须取决于每个单例所需的所有内容。同时,使用单例的任何人都必须依赖singleton.cpp库。

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

必须手动维护初始化顺序。

静态全局变量的构造点未与main中第一个表达式之前的所有内容进行排序。


我使用的一个不错的解决方案是创建一个保存单例内存的动态库。

要成为单例,您可以从CRTP帮助程序继承,该服务程序提供::Instance()内联方法。希望单身人士使用::Instance()

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

如果没有,它将创建新的存储并在其中构建对象。

在销毁静态局部变量生存期令牌时,它会减少引用计数。如果该引用计数达到0,则会在当前动态库中 local 销毁它。

单例的生存期现在是::Instance()创建的变量的生存期的并集。销毁发生在非类型擦除的代码中,因此我们不必担心DLL随代码被卸载。存储是中心。存储存储的DLL必须比Singleton系统的每个用户都要低,但是反过来又没有依赖关系,因此这不是一件容易的事。

这远非完美;单例和生存期是一个长期存在的问题,因为干净的程序关闭很难,并且由于单例的存在而变得更加困难。但是到目前为止,它已经在一个相当大的项目中起作用了。

答案 1 :(得分:0)

可以在您的情况下使用依赖项注入吗?即是否有一些序列化的代码创建每个类的实例,并将对该实例的引用传递到需要访问它们的任何其他实例的构造函数中?如果适用,这可以简化您的设计。理想情况下,您可以将一个单独的新创建的实例传递到每个构造函数中,以进一步减少耦合,但是似乎您需要共享状态。无论如何,也许有帮助。