单例模式(Singleton Pattern) 是一种常见的设计模式,它确保一个类只有一个实例,并提供全局访问点来获取该实例。换句话说,单例模式保证某个类在整个应用程序生命周期中只有一个实例,并提供一个全局的访问接口来获取该实例。

单例模式的关键特点:

  1. 唯一性:类只有一个实例。
  2. 全局访问:可以通过一个全局的静态方法访问到这个实例。
  3. 延迟初始化:单例实例的创建通常是懒加载的(即在第一次使用时才创建实例)。

单例模式的应用场景:

  • 需要控制某个类的实例数量(例如,配置管理器、日志记录器、数据库连接池等)。
  • 需要确保全局只有一个对象,并且该对象需要被多个地方共享。

单例模式的实现方式:

1. 懒汉式(Lazy Singleton):延迟实例化

这种方式只有在第一次访问时才创建实例,延迟到真正需要时才创建。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Singleton {
private:
static Singleton* instance; // 静态指针,指向唯一实例

// 构造函数私有,防止外部通过构造函数创建对象
Singleton() {}

public:
// 获取唯一实例的方法
static Singleton* getInstance() {
if (instance == nullptr) {
instance = new Singleton(); // 延迟实例化
}
return instance;
}

// 禁止拷贝构造和赋值操作,确保只有一个实例
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
};

// 初始化静态成员
Singleton* Singleton::instance = nullptr;
  • 优点:延迟实例化,只有在需要时才创建实例。
  • 缺点:线程不安全,如果在多线程环境中并发访问 getInstance,可能会导致创建多个实例。

2. 饿汉式(Eager Singleton):提前实例化

这种方式在程序启动时就创建实例,确保在整个生命周期中只有一个实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Singleton {
private:
static Singleton* instance; // 静态指针,指向唯一实例

// 构造函数私有
Singleton() {}

public:
// 获取唯一实例的方法
static Singleton* getInstance() {
return instance; // 返回实例
}

// 禁止拷贝构造和赋值操作
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
};

// 静态成员在程序启动时即初始化
Singleton* Singleton::instance = new Singleton();
  • 优点:实例在程序启动时就创建,线程安全。
  • 缺点:即使实例未被使用,也会在程序启动时创建。

3. 线程安全的懒汉式(Double-Checked Locking)

为了在多线程环境下保证单例的唯一性,使用锁机制来保证线程安全,同时避免每次访问时都进行锁操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Singleton {
private:
static Singleton* instance;
static std::mutex mtx; // 互斥锁

Singleton() {}

public:
static Singleton* getInstance() {
if (instance == nullptr) {
std::lock_guard<std::mutex> lock(mtx); // 加锁
if (instance == nullptr) {
instance = new Singleton(); // 双重检查
}
}
return instance;
}

Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
};

// 初始化静态成员
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;
  • 优点:在多线程环境下确保只创建一个实例,性能较好。
  • 缺点:稍微复杂,涉及锁机制。

4. 静态局部变量(C++11及以上)

利用静态局部变量,C++11标准保证静态局部变量的初始化是线程安全的。

1
2
3
4
5
6
7
8
9
10
11
12
13
class Singleton {
private:
Singleton() {}

public:
static Singleton& getInstance() {
static Singleton instance; // 静态局部变量,程序第一次调用时才会初始化
return instance;
}

Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
};
  • 优点:简单,线程安全,不需要显式的锁。
  • 缺点:实例是静态的,无法被销毁(在应用程序退出时才会被销毁)。

使用单例模式的注意事项:

  1. 全局访问点:单例模式提供全局访问点,但如果滥用会让代码变得难以测试和维护,因为任何地方都可以改变单例的状态。
  2. 线程安全:如果在多线程环境中使用,必须确保实例的创建过程是线程安全的。
  3. 内存泄漏:如果单例模式使用动态分配内存(例如 new),需要确保在程序结束时正确释放资源,防止内存泄漏。

什么时候使用单例模式:

  • 需要一个共享资源或者全局状态,且只需要一个实例(例如,日志管理、配置管理器)。
  • 想避免多次创建相同的对象,并且需要全局访问该对象。

© 2024 oymaster 使用 Stellar 创建

总访问量