本文主要说明单例模式的概念,应用,以及C++实现。
I、上帝视角看单例模式
1.1 单例模式特点
单例模式需要满足以下两个条件:
1、保证一个类只创建一个实例;
2、提供对该实例的全局访问点。
1.2 单例模式应用举例
如果系统需要类似的实体(有且仅由一个,且需要全局访问),就可以将其实现为一个单例。其主要应用包括:
1、日志类,一个应用往往只对应一个日志实例;
2、配置类,应用的配置集中管理,并提供全局访问;
3、管理器,如任务管理器就是一个典型的单例;
4、共享资源类,加载资源需要较长的时间,使用单例可以避免重复加载资源,并被多个地方共享访问。
II、单例模式实现
2.1 lazy Singleton
代码实现:
class Singleton
{
public:
/* 提供static的Instance()方法,作为全局访问点;
* 如果有现成的实例,则直接返回;
*如果没有,则将新生成的实例保存到私有的static属性中
*/
/* Instance()返回的是实例的引用而不是指针,如果是指针有被外部调用者delete的风险。
* 直到Instance()方法被访问,才会生成实例,这种特性被称为延迟初始化(Lazy Singleton)
*/
/* 但是这种方式不是线程安全的,比如有线程A和B
* 都通过了instance==nullptr判断,则两个线程会分配创建新实例,这样单例模式就被打破了。
*/
static Singleton& Instance() {
if (instance == nullptr)
instance = new Singleton;
return *instance;
}
private:
//构造函数与拷贝构造函数,拷贝赋值运算符都声明为私有方法,这样杜绝从外部生成新的实例
Singleton();
~Singleton();
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
private:
static Singleton* instance;
};
2.2 Eager Singleton
/* Eager Singleton */
/* 这种模式在程序开始就完成了实例的创建。与Lazy相反;
* 因为static成员在main函数之前初始化,所以没有线程安全的问题;
* 但是潜在的问题在于no-local static对象(函数外的static对象)
* 在不同编译单元中的初始化顺序是未定义的。
* 如果在初始化完成之前调用了Instance()方法就会返回一个未定义的实例。
* 也就是说不能保证先完成初始化。
*/
class Singleton
{
public:
static Singleton& Instance() {
return instance;
}
private:
Singleton();
~Singleton();
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
private:
static Singleton instance;
};
2.3 Meyers Singleton
/* Meyers Singleton*/
/* 下面是effective C++中提出的一种模式,使用local static对象
* 实现了当第一次访问Instance()方法时才创建实例。
*/
class Singleton
{
public:
static Singleton& Instance() {
static Singleton instance;
return instance;
}
private:
Singleton();
~Singleton();
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
};
2.4 Double-checked Locking Pattern
Lazy Singleton的一种线程安全改造是在Instance()
中每次判断是否为nullptr
前加锁,但是加锁是很慢的。
而实际上只有第一次实例创建的时候才需要加锁。那么在这之前判断一下实例有没有被创建就可以了,所以多在加锁之前加了一层判断,所以叫做Double-checked。理论上问题解决了,但实际上还是会有很多坑。这里不说明:
static Singleton& Instance() {
if (instance == nullptr) {
Lock lock; //局部作用域加锁,超出作用域,自动析构函数解锁
if (instance == nullptr) {
instance = new Singleton;
}
}
return *instance;
}
【参考】
[1] [单例模式及其C++实现] (https://zkt.name/dan-li-mo-shi-singleton-ji-c-shi-xian/)
欢迎转载,转载请注明出处wenmingxing 学而时习之单例模式