C ++单例与全局静态对象

时间:2009-09-23 02:42:56

标签: c++ static singleton global-variables

我的一位朋友今天问我为什么他更喜欢使用单身而不是全局静态物体? 我开始解释的方式是单例可以有状态与静态全局对象不会......但后来我不确定。因为这在C ++中...(我来自C#)

一方面有什么优势? (在C ++中)

8 个答案:

答案 0 :(得分:57)

实际上,在C ++中,首选方式是本地静态对象。

Printer & thePrinter() {
    static Printer printer;
    return printer;
}

这在技术上是单身,但这个函数甚至可以是类的静态方法。因此,与全局静态对象不同,它可以在使用之前进行保证,可以按任何顺序创建,从而可以在一个全局对象使用另一个非常常见的场景时无意义地失败。

通过调用new来创建新实例,通常做单例的方法是,在程序结束时调用对象析构函数。动态分配单例不会发生这种情况。

另一个积极的方面是,在创建单例之前无法访问单例,即使是从其他静态方法或子类也是如此。节省一些调试时间。

答案 1 :(得分:24)

在C ++中,不确定不同编译单元中静态对象的实例化顺序。因此,一个全局可能引用另一个未构造的全局,从而炸毁您的程序。单例模式通过将构造绑定到静态成员函数或自由函数来消除此问题。

有一个不错的摘要here

答案 2 :(得分:8)

  

我的一位朋友今天问我为什么他更喜欢使用单身而不是全局静态物体?我开始解释的方式是单例可以有状态与静态全局对象不会......但后来我不确定。因为这在C ++中...(我来自C#)

静态全局对象也可以在C#中具有状态:

class myclass {
 // can have state
 // ...
 public static myclass m = new myclass(); // globally accessible static instance, which can have state
}
  

一方面有什么优势? (在C ++中)

单例会破坏您的代码,而全局静态实例则不会。 关于单身人士的问题已经有无数问题了。 Here's oneand anotheror another

简而言之,单身人士会给你两件事:

  • 全局可访问的对象,
  • 保证只能创建一个实例。

如果我们只想要第一点,我们应该创建一个全局可访问的对象。 为什么我们会想要第二个?我们事先没有知道我们的代码将来如何使用,那么为什么要将其删除并删除可能有用的功能呢?当我们预测“我只需要一个实例”时,我们通常错误。 “我只需要一个实例”(正确的答案是创建一个实例)和“如果有多个实例,应用程序在任何情况下都无法正常运行”之间存在很大差异创建。它会崩溃,格式化用户的硬盘并在互联网上发布敏感数据“(这里的答案是:很可能你的应用程序坏了,但如果不是,那么是的,单身是你需要的)

答案 3 :(得分:4)

Singleton相对于全局静态对象的另一个好处是,因为构造函数是私有的,所以有一个非常清晰的编译器强制指令说“只能有一个”。

相比之下,使用全局静态对象,没有什么能阻止开发人员编写代码来创建此对象的附加实例。

额外约束的好处是可以保证对象的使用方式。

答案 4 :(得分:3)

原因1:
单身人士很容易制作,所以他们很懒散 虽然您可以使用全局变量执行此操作,但开发人员需要额外的工作。所以默认情况下总是初始化全局变量(除了一些带命名空间的特殊规则)。

因此,如果你的对象很大并且/或者构建起来很昂贵,你可能不想构建它,除非你真的必须使用它。

原因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();
        }
};

答案 5 :(得分:2)

使用Singleton(“首次使用时构造”)习语,可以避免使用static initialization order fiasco

答案 6 :(得分:0)

在C ++中,两者在实际有用性方面没有太大差异。全局对象当然可以保持自己的状态(可能还有其他全局变量,但我不推荐它)。如果你要使用全局或单例(并且有很多理由不这样做),那么在全局对象上使用单例的最大原因是,对于单例,你可以通过让几个类继承来实现动态多态性单身基类。

答案 7 :(得分:-1)

好吧,真的有两个原因可以选择单身人士。一个是每个人都在谈论的静态秩序。

另一种方法是在使用代码时阻止某人做这样的事情:

CoolThing blah;
gs_coolGlobalStaticThing = blah;

或更糟糕的是:

gs_coolGlobalStaticThing = {};

封装方面将保护您的实例免受白痴和恶意混蛋。

相关问题