我正在研究一个C ++项目,该项目具有多个必须为单例的类,它们之间具有依赖性(初始化的顺序很重要)。
我想出了这个解决方案:
class MySingleton1 { protected: MySingleton1(); }
#include "MySingleton1.hpp" #include "MySingleton2.hpp" class Singletons : public MySingleton1, public MySingleton2 {} static Singletons s_singletons;
template<> MySingleton1& getSingleton() { return s_singletons; } template<> MySingleton2& getSingleton() { return s_singletons; }
template <class TSingleton> TSingleton& getSingleton();
优势:
低耦合:
初始化顺序可以通过更改Singletons类的继承顺序来控制
缺点:
据我所知,这实际上还算不错,因此我想保留这种方式,但我寻求您的反馈 (这样做比编程社区哪个地方更好?)。
您看到此解决方案有哪些其他优点/缺点?
您建议什么替代品?
答案 0 :(得分:6)
这迫使Singletons集中化,这可能使更复杂项目中的依赖关系混乱。拥有singleton.cpp
的库必须取决于每个单例所需的所有内容。同时,使用单例的任何人都必须依赖singleton.cpp
库。
基本上,您的代码只能在单片非模块化项目中工作。将其扩展到多个动态库几乎是不可能的。
必须手动维护初始化顺序。
静态全局变量的构造点未与main
中第一个表达式之前的所有内容进行排序。
我使用的一个不错的解决方案是创建一个保存单例内存的动态库。
要成为单例,您可以从CRTP帮助程序继承,该服务程序提供::Instance()
内联方法。希望单身人士使用::Instance()
。
::Instance()
创建一个静态局部变量生存期令牌。然后,它尝试从主DLL获取单例的存储。如果已经创建了对象,则只需将存储转换为对象类型,并增加其引用计数。
如果没有,它将创建新的存储并在其中构建对象。
在销毁静态局部变量生存期令牌时,它会减少引用计数。如果该引用计数达到0,则会在当前动态库中 local 销毁它。
单例的生存期现在是::Instance()
创建的变量的生存期的并集。销毁发生在非类型擦除的代码中,因此我们不必担心DLL随代码被卸载。存储是中心。存储存储的DLL必须比Singleton系统的每个用户都要低,但是反过来又没有依赖关系,因此这不是一件容易的事。
这远非完美;单例和生存期是一个长期存在的问题,因为干净的程序关闭很难,并且由于单例的存在而变得更加困难。但是到目前为止,它已经在一个相当大的项目中起作用了。
答案 1 :(得分:0)
可以在您的情况下使用依赖项注入吗?即是否有一些序列化的代码创建每个类的实例,并将对该实例的引用传递到需要访问它们的任何其他实例的构造函数中?如果适用,这可以简化您的设计。理想情况下,您可以将一个单独的新创建的实例传递到每个构造函数中,以进一步减少耦合,但是似乎您需要共享状态。无论如何,也许有帮助。