CppCoreGuidelines I.3 避免使用单例模式
14 March 2022
I.3: Avoid singletons
理由
单例( Singleton )其实只不过是伪装了的复杂的全局对象:
例子
class Singleton { // ... lots of stuff to ensure that only one Singleton object is created, // that it is initialized properly, etc. };
另外一个问题是,单例的形式也有很多种……
注意
如果希望全局对象的值不可变,可以把它声明为 const
或 constexpr
。
例外
可以用最简单的单例模式。第一次使用的时候,把它初始化。
typedef int X; X& myX() { static X my_x {3}; return my_x; } int main() { cout << myX() << endl; cout << myX(); return 0; }
3 3
以上是解决初始化顺序问题的最有效方法之一。在多线程环境下,初始化静态对象不会导致竞争条件。除非是在构造器中访问了共享对象。
局部静态变量的初始会不会导致竞争条件。但是对象的解构如果需要同步进行的话,就要用简单一些的解决办法。比如:
X& myX() { static auto p = new X {3}; return *p; // potential leak }
以上代码返回的是一个指针,就需要在某个地方以恰当的线程安全的方式删除其存储。这样就容易出错,所以尽量避免,除非:
myX
是一个多线程代码,X
对象需要释放,X
的解构器代码同步进行。
如果定义了单实例类,该类只创建了一个对象,那么 myX
函数就不是单实例。此种情况,也非本规则的例外。即也要遵循本规则。
强化
- 找到名字中有 singleton 的类
- 找到只创建一个对象的类:数对象数,检查构造器
- 如类有一公开静态函数,函数里本地静态构造了此类的一对象,并作为指针或引用返回此对象。禁之。