C++ 单例 vs. 全局静态对象

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1463707/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 20:04:52  来源:igfitidea点击:

C++ singleton vs. global static object

c++staticsingletonglobal-variables

提问by vava

A friend of mine today asked me why should he prefer use of singleton over global static object? The way I started it to explain was that the singleton can have state vs. static global object won't...but then I wasn't sure..because this in C++.. (I was coming from C#)

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

What are the advantages one over the other? (in C++)

一个比另一个有什么优势?(在 C++ 中)

回答by vava

Actually, in C++ preferred way is local static object.

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

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

This is technically a singleton though, this function can even be a static method of a class. So it guaranties to be constructed before used unlike with global static objects, that can be created in any order, making it possible to fail unconsistently when one global object uses another, quite a common scenario.

虽然这在技术上是一个单例,但这个函数甚至可以是一个类的静态方法。因此,与全局静态对象不同,它保证在使用之前先构造,可以以任何顺序创建,这使得当一个全局对象使用另一个全局对象时可能会不一致地失败,这是一种很常见的情况。

What makes it better than common way of doing singletons with creating new instance by calling newis that object destructor will be called at the end of a program. It won't happen with dynamically allocated singleton.

与通过调用创建新实例的常见方法相比,它比普通方法更好的new是对象析构函数将在程序结束时调用。动态分配的单例不会发生这种情况。

Another positive side is there's no way to access singleton before it gets created, even from other static methods or from subclasses. Saves you some debugging time.

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

回答by rlbond

In C++, the order of instantiation of static objects in different compilation units is undefined. Thus it's possible for one global to reference another which is not constructed, blowing up your program. The singleton pattern removes this problem by tying construction to a static member function or free function.

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

There's a decent summary here.

有一个像样的总结在这里

回答by jalf

A friend of mine today asked me why should he prefer use of singleton over global static object? The way I started it to explain was that the singleton can have state vs. static global object won't...but then I wasn't sure..because this in C++.. (I was coming from C#)

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

A static global object can have state in C# as well:

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

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

What are the advantages one over the other? (in C++)

一个比另一个有什么优势?(在 C++ 中)

A singleton cripples your code, a global static instance does not. There are countless questions on SO about the problems with singletons already. Here's one, and another, or another.

单例会削弱您的代码,而全局静态实例不会。关于单身人士的问题已经有无数的问题了。这是一个另一个或另一个

In short, a singleton gives you two things:

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

  • a globally accessible object, and
  • a guarantee that only one instance can be created.
  • 一个全局可访问的对象,以及
  • 保证只能创建一个实例。

If we want just the first point, we should create a globally accessible object. And whywould we ever want the second? We don't knowin advance how our code may be used in the future, so why nail it down and remove what may be useful functionality? We're usually wrongwhen we predict that "I'll only need one instance". And there's a big difference between "I'll only need one instance" (correct answer is then to createone instance), and "the application can't under any circumstances run correctly if more than one instance is created. It will crash, format the user's harddrive and publish sensitive data on the internet" (the answer here is then: Most likely your app is broken, but ifit isn't, then yes, a singleton is what you need)

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

回答by Andrew Shepherd

Another benefit of the Singleton over the global static object is that because the constructor is private, there is a very clear, compiler enforced directive saying "There can only be one".

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

In comparison, with the global static object, there will be nothing stopping a developer writing code that creates an additional instance of this object.

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

The benefit of the extra constraint is that you have a guarantee as to how the object will be used.

额外约束的好处是您可以保证如何使用对象。

回答by Martin York

Reason 1:
Singletons are easy to make so they are lazy build.
While you can do this with globals it take extra work by the developer. So by default globals are always initialized (apart from some special rules with namespaces).

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

So if your object is large and/or expensive to build you may not want to build it unless you really have to use it.

因此,如果您的对象很大和/或构建成本很高,您可能不想构建它,除非您真的必须使用它。

Reason 2:
Order of initialization (and destruction) problem.

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

回答by aJ.

Using Singleton("construct on first use") idiom, you can avoid static initialization order fiasco

使用 Singleton("construct on first use") 习惯用法,可以避免静态初始化顺序失败

回答by coppro

In C++, there's not a huge amount of difference between the two in terms of actual usefulness. A global object can of course maintain its own state (possibly with other global variables, though I don't recommend it). If you're going to use a global or a singleton (and there are many reasons not to), the biggest reason to use a singleton over a global object is that with a singleton, you can have dynamic polymorphism by having several classes inheriting from a singleton base class.

在 C++ 中,就实际用途而言,两者之间没有太大区别。全局对象当然可以保持自己的状态(可能与其他全局变量一起使用,但我不推荐这样做)。如果您打算使用全局或单例(并且有很多原因不这样做),那么在全局对象上使用单例的最大原因是,对于单例,您可以通过继承多个类来实现动态多态性单例基类。

回答by Sean

OK, there are two reasons to go with a singleton really. One is the static order thing everyone's talking about.

好吧,确实有两个理由使用单身人士。一个是每个人都在谈论的静态顺序。

The other is to prevent someone from doing something like this when using your code:

另一个是防止有人在使用你的代码时做这样的事情:

CoolThing blah;
gs_coolGlobalStaticThing = blah;

or, even worse:

或者,更糟糕的是:

gs_coolGlobalStaticThing = {};

The encapsulation aspect will protect your instance from idiots and malicious jerks.

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