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

问题描述

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

我想出了这个解决方案:

  1. 我想成为单例的所有类都有受保护的构造函数,例如:
class MySingleton1
{
protected:
    MySingleton1();
}
  1. 有一个源文件singleton_factory.cpp包含一个实例化的类Singletons,它派生自我想成为 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();

优点:

缺点:

所以,据我所知,这实际上相当不错,所以我想把它保留下来,但我正在征求您的反馈意见(还有比编程社区更好的地方吗?)。

您认为此解决方案有哪些额外的优势/劣势

你有什么替代方案

标签: c++design-patternssingleton

解决方案


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

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

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

静态全局变量的构造点与main.


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

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

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

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

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

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

这远非完美。单例和生命周期是一个持续存在的问题,因为干净的程序关闭是困难的,而且单例的存在也变得更加困难。但到目前为止,它已经在一个相当大的项目中发挥了作用。


推荐阅读