单例模式
方法1:C++11 线程不安全懒汉模式(不推荐)
懒汉式单例模式在第一次使用时才创建实例,但这种方式在多线程环境下可能会出现问题。
class Singleton {
private:
static Singleton* instance; // 静态指针,用于存储单例对象
Singleton() {} // 私有构造函数,防止外部直接构造
public:
static Singleton* getInstance() {
if (instance == nullptr) { // 检查是否已经创建了实例
instance = new Singleton();
}
return instance;
}
};
// 初始化静态成员变量
Singleton* Singleton::instance = nullptr;
int main() {
Singleton* s1 = Singleton::getInstance();
Singleton* s2 = Singleton::getInstance();
// s1 和 s2 指向同一个对象
return 0;
}
方法2:懒汉式单例模式(线程安全)
为了确保线程安全,可以在getInstance函数中使用互斥锁(std::mutex)
#include <mutex>
class Singleton {
private:
static Singleton* instance; // 静态指针,用于存储单例对象
static std::mutex mutex_; // 互斥锁
Singleton() {} // 私有构造函数,防止外部直接构造
public:
static Singleton* getInstance() {
std::lock_guard<std::mutex> lock(mutex_); // 加锁
if (instance == nullptr) { // 检查是否已经创建了实例
instance = new Singleton();
}
return instance;
}
};
// 初始化静态成员变量
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mutex_;
int main() {
Singleton* s1 = Singleton::getInstance();
Singleton* s2 = Singleton::getInstance();
// s1 和 s2 指向同一个对象
return 0;
}
方法3:C++11 基于局部静态变量的单例模式
利用 C++11 的 static
特性实现线程安全的延迟初始化:
class Singleton {
public:
// 删除拷贝构造和赋值运算符
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
// 全局访问点
static Singleton& getInstance() {
static Singleton instance; // C++11保证线程安全的静态局部变量初始化
return instance;
}
private:
Singleton() {} // 私有构造函数
~Singleton() {} // 私有析构函数
};
// 使用示例:
Singleton& obj = Singleton::getInstance();
优点:
- 线程安全(C++11标准保证)
- 延迟初始化(首次调用时创建)
- 代码简洁
方法4:双重检查锁定(传统线程安全)
适用于 C++11 之前的版本:
#include <mutex>
#include <atomic>
class Singleton {
public:
static Singleton* getInstance() {
Singleton* tmp = instance.load(std::memory_order_acquire);
if (tmp == nullptr) { // 第一次检查
std::lock_guard<std::mutex> lock(mutex);
tmp = instance.load(std::memory_order_relaxed);
if (tmp == nullptr) { // 第二次检查
tmp = new Singleton();
instance.store(tmp, std::memory_order_release);
}
}
return tmp;
}
// 删除拷贝和赋值
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
private:
Singleton() {} // 私有构造函数
~Singleton() {} // 私有析构函数
static std::atomic<Singleton*> instance; // 原子指针
static std::mutex mutex; // 互斥锁
};
// 初始化静态成员
std::atomic<Singleton*> Singleton::instance{nullptr};
std::mutex Singleton::mutex;
// 使用示例:
Singleton* obj = Singleton::getInstance();
优点:
- 线程安全
- 延迟初始化
- 高性能(避免每次调用加锁)
方法5:饿汉模式(程序启动时初始化)
线程安全但提前初始化:
class Singleton {
public:
static Singleton& getInstance() {
return instance; // 直接返回已初始化的实例
}
// 删除拷贝和赋值
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
private:
Singleton() {} // 私有构造函数
~Singleton() {} // 私有析构函数
static Singleton instance; // 程序启动时初始化
};
// 初始化静态成员(在.cpp文件中)
Singleton Singleton::instance;
// 使用示例:
Singleton& obj = Singleton::getInstance();
优点:
- 线程安全
- 实现简单
缺点:
- 程序启动时即初始化,可能浪费资源
- 无法处理依赖其他模块初始化的情况
单例模式的关键点
- 构造函数私有化:禁止外部创建实例
- 删除拷贝和赋值:防止通过拷贝创建新对象
- 全局访问点:静态方法提供唯一访问入口
- 线程安全:根据场景选择实现方式
注意事项
- 避免滥用单例模式(可能导致代码耦合度高)
- 单例对象的销毁需要谨慎处理(一般程序结束时自动释放)
- 多线程环境下优先使用 C++11 的
static
实现