单例模式

单例模式

1.何为单例模式

​ 单例模式的理念是,应用程序中只能有一个特定组件的实例。保证一个类只有一个实例,并提供一个该实例的全局访问点。

2.单例模式的意义和使用场景

​ 有的类需要保证只有一个实例才能确保其逻辑正确性以及保持良好的效率。

3.单例模式的实现

​ 只需要将单例模式的构造函数、拷贝构造函数、移动构造函数、拷贝赋值函数删除,再提供一个返回唯一实例的指针的函数就可以了。

4.多线程下的单例模式

单例模式的两种实现方式

​ 1.饿汉式:唯一实例在定义时就初始化,这种方式是线程安全的。但是它会使程序启动事件增加,浪费资源。

1
2
3
4
5
6
7
8
9
10
11
12
class Singleton {
private:
static Singleton* instance;
Singleton() {} // 将构造函数设为私有,禁止外部实例化

public:
static Singleton* getInstance() {
return instance;
}
};

Singleton* Singleton::instance = new Singleton(); // 在定义静态成员变量时直接初始化

​ 2.懒汉式:延迟初始化的方式,即在首次使用时才创建单例对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Singleton {
private:
static Singleton* instance;
Singleton() {} // 将构造函数设为私有,禁止外部实例化

public:
static Singleton* getInstance() {
if (instance == nullptr) {
instance = new Singleton();
}
return instance;
}
};

Singleton* Singleton::instance = nullptr; // 初始化静态成员变量

​ 这种形式的创建存在线程安全问题,有两种解决方案。一是在 getInstance()函数的第一行上锁,但这种方式十分浪费资源,在高并发环境下不可取。

​ 第二种是使用双重校验锁。这种双重校验锁在c++11前会出现问题,因为编译器优化可能会分配内存后直接将地址返回给指针。导致在一段时间内,指针指向未完全初始化的内存。而其他线程可能会将这个未初始化完成的内存返回。

​ C++11标准对静态局部变量的初始化进行了明确规定:静态局部变量在第一次访问时进行初始化,且只有一个线程能够执行初始化过程。这确保了静态局部变量的线程安全性。

1
2
3
4
5
6
7
8
static Singleton* getInstance() {
if (instance == nullptr) {
std::lock_guard<std::mutex> lock(mtx); // 加锁
if (instance == nullptr) { // 双重检查
instance = new Singleton();
}
}
return instance;