单例在 C++ 中如何精确工作

How precisely does a singleton work in C++

我了解单身人士的作用以及您使用单身人士的原因。但是我不明白他们是如何工作的。如果之前已经创建过一次单例并且在其他地方调用了“get instance”方法,它如何知道单例的原始实例在内存中的哪个位置?通过阅读代码,我无法理解它的来源。下面是来自 Microsoft MSDN website.

的简单示例
class Singleton {
public: 
    static Singleton* Instance();
protected: 
    Singleton();
private:
    static Singleton* _instance;
}

// Implementation 
Singleton* Singleton::_instance = 0;

Singleton* Singleton::Instance() {
    if (_instance == 0) {
        _instance = new Singleton;
    }
    return _instance;
}

我很确定它来自这里的这一行

Singleton* Singleton::_instance = 0;

但我不知道那条线到底是做什么的,也不知道它是如何工作的。

提前致谢

单例有时非常有用。

这就是说:

Singleton* Singleton::Instance() {
    if (_instance == 0) {
        _instance = new Singleton;
    }
    return _instance;
}

是否已创建此对象(在本例中为 Singleton 类型),如果已创建,return。如果不创建新的 "Singleton" 对象并 return 它。

换句话说,无论您调用 Instance() 方法多少次,它对您来说总是 return 相同的对象。

这是一个不那么令人困惑的例子。我们只保留 Singleton 作为设计模式名称,而不将其用作 Class 名称。

Logger* Logger::m_pInstance = NULL; 

/* Use this to get the instance of Logger instead of "new" */
Logger* Logger::Instance()
{

     if (!m_pInstance) {  // Only allow one instance of class to be generated.
         m_pInstance = new Logger;
     }

     return m_pInstance;
}


/* some other method in the logger class */
bool Logger::openLogFile(std::string _logFile)
{

   ...
   ...
   ...

}

所以基本上,如果您想要这个 class 的实例,您可以调用 instance() 方法。它将始终 return 与您完全相同的对象。

是的,有些人出于某种原因不喜欢 Singleton...不知道为什么。所有的模式都有它们的位置和用途。

学习尽可能多的设计模式以及何时使用它们,总比不知道它们要好。

https://en.wikipedia.org/wiki/Software_design_pattern

真是个可怕的例子。一起来看看详情:

    static Singleton* Instance();

函数应该returnSingleton&,而不是Singleton*

protected: 
    Singleton();

protected 仅对 class 设计为派生的 es 有意义。从 Singleton 派生没有多大意义。充其量,这是一个奇特的特例。单例构造函数通常是 private.

Singleton* Singleton::_instance = 0;

自 C++11 起,nullptr 应该用于空指针。

Singleton* Singleton::Instance() {
    if (_instance == 0) {
        _instance = new Singleton;
    }
    return _instance;
}

不是线程安全的。假设有 3 个线程(A、B 和 C)同时调用 Instance()。他们三人首次同时达到 if (_instance == 0)。因此,条件对它们都成立,所以它们都进入 if 块 - 导致创建 三个 个实例!

I'm pretty sure it comes from this line here

Singleton* Singleton::_instance = 0;

But I have no idea what that line actually does or how it works.

初始化static_instanceSingletonclass的成员变量。 static 在此上下文中意味着变量存在 独立 任何 Singleton 实例,因此您可以在 static 成员函数中访问它,例如 Instance().


自 C++11 起,实现单例的线程安全方法是使用 static 局部变量:

Singleton& Singleton::Instance() {
    static Singleton instance;
    return instance;
}

该技术由来已久,但自C++11起才成为线程安全的,因为只有C++11标准才正式承认多线程的存在,包括对局部的一定保证static变量。

这种技术的缺点是,如果您有多个单例 class 并且一个单例的析构函数访问另一个单例,您可以 运行 进入销毁顺序问题。

有很多方法可以解决这个问题,但我不会在这里详细介绍,因为现在您已经了解了一些关于 Singleton 的知识 - 不要使用该模式。

现在大多数程序员都通过惨痛的教训了解到,单例只是伪装的全局变量,应该很少使用。它们在您的代码中创建全局依赖关系,使测试和模块化变得更加困难或不可能, 很难正确和安全地实施。辛格尔顿是四人帮书中的头号害群之马


顺便看看微软自己在你提到的页面顶部是怎么说的:

This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies.

If the singleton has been created once before and the "get instance" method has been called somewhere else how does it know where in memory the original instance of the singleton is?

静态数据通常存储在可执行文件的 .data 部分。

当您的代码使用静态数据时,它会被翻译成汇编指令,从数据部分引用一些绝对地址,例如

A1 00 F0 22 01       mov         eax,dword ptr ds:[0122F000h]

您的代码是在假设您的程序将被加载到某个预期的基址下编译和链接的 address.This 情况并非总是如此,因此您的可执行文件还包含重定位部分,其中包含有关您的位置的偏移信息文件是那些绝对地址。

当您的程序加载到内存中时,OS 会注意将这些绝对地址替换为真实地址。