我在这里就stackoverflow做了一些关于这个主题的研究,但我没有找到一个答案,我可以从哪里学习单例类如何工作。我已经知道单例类只能有一个实例。任何人都可以解释我 - 或者链接我一个教程 - 如何创建最基本的单例类并逐行告诉我为什么/它如何工作? 我遇到的麻烦是,我查找的答案和一些教程并没有真正解释为什么我应该将某个变量或函数声明为静态,指针等。
答案 0 :(得分:2)
<强> Discalimer 强>
通常,应尽量避免使用单例和/或全局对象。应该明确传递函数require的对象。这样可以在并行化代码时通过传递模拟对象,调试和减少争用来轻松测试函数。例如,我的应用程序中唯一的全局对象是记录器(类似于标准I / O流)和特定于线程的事件循环引擎。
使用单例或全局对象的唯一原因是避免在所有函数调用中传递它的麻烦。例如。您不希望通过每次调用传递记录器对象,但是没有必要创建许多本地或成员记录器对象来节省空间和时间。
方法1
最基本的单例是在运行时动态初始化阶段初始化的全局对象,例如:
// singleton.h
class Singleton { /*...*/ };
extern Singleton singleton;
// singleton.cc
#include "singleton.h"
extern Singleton singleton(/*...*/);
好处:
main
之前初始化。singleton
什么是单例,而不是类本身。缺点:
main
之前可能无法使用某些构造函数参数。也可以在输入main
之前使用此类对象,方法是确保在使用Schwarz Counter进行首次访问之前对其进行初始化(同样的方法std::cout
和朋友初始化)。< / p>
方法2
另一种选择是拥有一个指向对象的全局指针。该指针在main
的早期初始化,并在main
堆栈上创建了一个对象。
E.g:
// singleton.h
class Singleton { /*...*/ };
extern Singleton* singleton;
// main.cc
int main() {
Singleton the_singleton(/*...*/);
singleton = &the_singleton;
// at main end
singleton = nullptr;
}
与方法1相比的好处。
方法3
C ++ 11中的函数作用域static (gcc在C ++ 11之前做过)对象:
// singleton.h
class Singleton { /*...*/ };
Singleton& get_singleton();
// singleton.cc
Singleton& get_singleton() {
static Singleton singleton;
return singleton;
}
方法1的优点和缺点。
方法4
双重检查锁定的单身人士。 Not necessary in C++11,因为函数作用域static 为您进行线程安全初始化。
答案 1 :(得分:2)
勺子男孩:不要尝试单身课。这是不可能。不良做法。相反......只是试图实现真相。Neo:真相是什么?
勺子男孩:没有单身人士。
Neo:没有单身人士?
Spoon boy:然后你会看到,不仅仅是一个实例的类,只有你需要一个实例。
我想说的是:作为一个班级作者,永远不要强迫这个班级成为单身人士。仅仅因为您认为系统今天只需要一个Logger
对象,并不意味着明天您可能不需要两个(例如,一个用于Windows应用程序事件日志,一个用于系统事件日志)。
认为你的thread_pool
课应该是单身人士?好吧,我需要一个公平的线程池和我的一个应用程序中的LIFO线程池。
如果要创建N Agent
个对象,并且它们都需要共享一个Logger
对象,请不要将Logger
写为单例 - 而是使用类似:
// agent.h
class Agent {
...
private:
Logger& GetLogger();
}
// agent.cpp
Logger& Agent::GetLogger() {
static Logger TheOne;
return The One;
}
毕竟,Agent
需要Logger
才能成为单身人士 - 而不是Logger
本身!