C ++单例与全局静态对象
我的一个朋友今天问我为什么他更喜欢使用singleton而不是全局静态对象呢? 我开始解释的方式是,单身可以有状态与静态全局对象不会…但后来我不确定..因为这在C ++ ..(我来自C#)
彼此有什么优势? (在C ++中)
实际上,在C ++中首选的方式是本地静态对象。
Printer & thePrinter() { static Printer printer; return printer; }
这在技术上虽然是单身,但是这个function甚至可以是一个类的静态方法。 因此,与使用全局静态对象(可以按任意顺序创build)不同,可以在使用之前构造保证,从而可以在一个全局对象使用另一个全局对象时出现不一致的失败。
什么比通过调用new
来创build新实例的单身人士的常见方式更好是因为对象析构函数将在程序结束时被调用。 dynamic分配的单例不会发生。
另一个积极的方面是在创build之前无法访问单例,即使从其他静态方法或从子类中也是如此。 节省您一些debugging时间。
在C ++中,静态对象在不同编译单元中的实例化顺序是不确定的。 因此,一个全局可能会引用另一个没有构build的另一个,炸毁你的程序。 单例模式通过将构造绑定到静态成员函数或自由函数来消除此问题。
这里有一个体面的总结。
我的一个朋友今天问我为什么他更喜欢使用singleton而不是全局静态对象呢? 我开始解释的方式是,单身可以有状态与静态全局对象不会…但后来我不知道..因为这在C ++ ..(我来自C#)
一个静态的全局对象也可以在C#中拥有状态:
class myclass { // can have state // ... public static myclass m = new myclass(); // globally accessible static instance, which can have state }
彼此有什么优势? (在C ++中)
一个单身人士瘫痪你的代码,一个全局静态实例不会。 关于单身人士的问题已经有无数个问题了。 这是一个 , 另一个 , 或另一个 。
总之,一个单身人士给你两件事情:
- 一个全局可访问的对象,和
- 保证只能创build一个实例。
如果我们只想要第一点,我们应该创build一个全球可访问的对象。 而为什么我们会想要第二个呢? 我们并不知道我们的代码将来如何使用,所以为什么要把它弄明白,并删除可能有用的function呢? 当我们预测“我只需要一个实例”时,我们通常是错误的 。 而且“我只需要一个实例”(正确的答案就是创build一个实例)和“应用程序在任何情况下都不能正确运行,如果创build了多个实例,它将会崩溃,格式化用户的硬盘,并在互联网上发布敏感数据“(这里的答案是:很可能你的应用程序是坏的,但如果不是,那么是的,单身就是你需要的)
原因1:
单身人士很容易做,所以他们是懒惰的build设。
虽然你可以用全局variables来做这件事,但开发人员需要额外的工作。 所以默认情况下,全局variables总是被初始化(除了一些特殊的命名空间规则外)。
所以如果你的对象很大或者很贵,你可能不想构build它,除非你真的需要使用它。
原因2:
初始化(和销毁)问题的顺序。
GlobalRes& getGlobalRes() { static GlobalRes instance; // Lazily initialized. return instance; } GlobalResTwo& getGlobalResTwo() { static GlobalResTwo instance; // Lazy again. return instance; } // Order of destruction problem. // The destructor of this object uses another global object so // the order of destruction is important. class GlobalResTwo { public: GlobalResTwo() { getGlobalRes(); // At this point globalRes is fully initialized. // Because it is fully initialized before this object it will be destroyed // after this object is destroyed (Guaranteed) } ~GlobalResTwo() { // It is safe to use globalRes because we know it will not be destroyed // before this object. getGlobalRes().doStuff(); } };
使用Singleton(“首次使用构造”)成语时,可以避免静态初始化顺序的失败
Singleton相对于全局静态对象的另一个好处是,因为构造函数是私有的,所以有一个非常清晰的编译器强制指令,说“只能有一个”。
与全局静态对象相比,不会有任何东西阻止开发人员编写代码来创build该对象的附加实例。
额外的限制的好处是你有一个保证,如何使用对象。
在C ++中,两者在实际用途上并没有太大的差别。 一个全局对象当然可以保持自己的状态(可能还有其他全局variables,尽pipe我不推荐它)。 如果你打算使用全局或者单例(有很多理由不这样做),那么使用单例代替全局对象的最大理由是,对于单例,你可以通过让几个类inheritancedynamic多态一个单独的基类。
好的,真的有一个单身人士有两个原因。 一个是每个人都在谈论的静态订单。
另一个是在使用你的代码时防止有人做这样的事情:
CoolThing blah; gs_coolGlobalStaticThing = blah;
或者更糟的是:
gs_coolGlobalStaticThing = {};
封装方面将保护您的实例免受白痴和恶意抽搐。