- 概念
- 饿汉模式
- 懒汉模式
- 饿汉模式和懒汉模式的优缺点
单例模式:一个类只能创建一个对象,即单例模式,该模式可以保证系统中该类只有一个实例,并提供一个访问它的全
局访问点,该实例被所有程序模块共享
单例模式的实现分为饿汉模式和懒汉模式
饿汉模式
程序启动时就创建一个唯一的实例对象,去加载所有的资源(预加载)
- 构造函数私有化
- 防拷贝
- 在类内创建一个静态对象,静态对象是属于类的,唯一的一份,符合单例模式的要求
- 提供一个静态接口,返回对象的指针或者引用
在静态区创建对象
class Singleton {
public:
static Singleton& GetInstance(){
return _inst;
}
private:
//构造函数私有化
Singleton(){}
//防拷贝
Singleton(const Singleton&) = delete;
Singleton operator=(Singleton) = delete;
//创建静态对象,保证只有一个对象
static Singleton _inst;
};
Singleton Singleton::_inst;
在堆上创建对象
class Singleton {
public:
static Singleton* GetInstance() {
return _inst;
}
private:
//构造函数私有化
Singleton() {}
//防拷贝
Singleton(const Singleton&) = delete;
Singleton operator=(Singleton) = delete;
//创建静态对象,保证只有一个对象
static Singleton* _inst;
};
Singleton* Singleton::_inst = new Singleton;
饿汉模式是在类加载阶段就已经完成了对象的初始化,所以饿汉模式不存在线程安全问题
但是正因为如此,如果单例对象构造十分耗时或者占用很多资源,比如加载插件啊, 初始化网络连接啊,读取文件啊等等,而有可能该对象程序运行时不会用到,那么也要在程序一开始就进行初始化,就会导致程序启动时非常的缓慢。 所以这种情况使用懒汉模式(延迟加载)更好
懒汉模式
堆区版本的懒汉模式
- 构造函数私有化
- 防拷贝
- 创建一个静态对象指针,提供一个静态接口
- 调用这个静态接口的时候,如果还没有创建对象,就new一个对象返回对象地址,如果对象已经存在,就什么都不做
- 在进行对象是否存在的判断时,要保证线程安全
- 如果要对创建的对象进行释放,可以添加一个静态del函数,或者添加一个垃圾回收类,在对象生命周期结束时自动释放资源
class Singleton {
public:
static Singleton* GetInstance() {
//双检查,在没有对象创建的时候才去获取锁,创建对象
if (_inst == nullptr) {
_mtx.lock();
if (_inst == nullptr) {
_inst = new Singleton;
}
_mtx.unlock();
}
return _inst;
}
static void DelInstance() {
_mtx.lock();
if (_inst) {
delete _inst;
_inst = nullptr;
}
_mtx.unlock();
}
// 实现一个内嵌垃圾回收类
class CGarbo {
public:
~CGarbo() {
if (_inst) {
delete _inst;
_inst = nullptr;
}
}
};
private:
//构造函数私有化
Singleton() {}
//防拷贝
Singleton(const Singleton&) = delete;
Singleton operator=(Singleton) = delete;
//创建静态对象,保证只有一个对象
static Singleton* _inst;
static mutex _mtx;
static CGarbo _cg;
};
Singleton* Singleton::_inst = nullptr;
mutex Singleton::_mtx;
Singleton::CGarbo Singleton::_cg;
静态区版本的懒汉模式
class Singleton {
public:
static Singleton& GetInstance() {
static Singleton inst;
return inst;
}
private:
//构造函数私有化
Singleton() {}
//防拷贝
Singleton(const Singleton&) = delete;
Singleton operator=(Singleton) = delete;
};
这种方法不必考虑线程安全问题,编写十分简单
这种方式有一些缺陷
- 对象创建在静态区,如果对象太大就不适合用这种方法
- 无法手动释放资源,只有对象生命周期到期时才会自动释放
饿汉模式和懒汉模式的优缺点
饿汉模式
优点
- 简单
缺点
- 程序启动时候就要加载资源,如果需要初始化的资源过大,就会导致程序的启动速度变慢,影响用户体验
- 如果有多个单例类,假设之间存在着依赖关系,例如B依赖A,要求A单例先创建初始化,B单例再创建初始化,此时就不能够使用饿汉模式,因为无法保证其初始化顺序,而使用懒汉模式则可以手动控制
懒汉模式
优点
- 延迟加载,程序启动的时候不会初始化类,不会影响程序的启动速度
- 可以手动控制类的初始化顺序
缺点
- 需要考虑判断的线程安全问题,效率会有所降低
- 编写较为复杂



