在 C++ 中实现单例模式有多种方法,以下是线程安全的现代 C++ 实现方式(推荐 C++11 及以上版本):
1. Meyers’ Singleton(推荐)
class Singleton {
public:
// 删除拷贝构造和赋值运算符
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
static Singleton& getInstance() {
static Singleton instance; // C++11 保证静态局部变量线程安全
return instance;
}
private:
Singleton() = default; // 私有构造函数
~Singleton() = default; // 私有析构函数
};
2. 传统线程安全实现(双重检查锁定)
#include <mutex>
class Singleton {
public:
static Singleton* getInstance() {
if (instance == nullptr) {
std::lock_guard<std::mutex> lock(mutex_);
if (instance == nullptr) {
instance = new Singleton();
}
}
return instance;
}
// 删除拷贝构造和赋值运算符
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
private:
Singleton() = default;
~Singleton() = default;
static Singleton* instance;
static std::mutex mutex_;
};
// 初始化静态成员
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mutex_;
3. 饿汉式(程序启动时初始化)
class Singleton {
public:
static Singleton& getInstance() {
return instance;
}
// 删除拷贝构造和赋值运算符
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
private:
Singleton() = default;
~Singleton() = default;
static Singleton instance;
};
// 在源文件中初始化
Singleton Singleton::instance;
4.关键要素
- 私有构造函数:防止外部创建实例
- 删除拷贝构造和赋值运算符:防止对象复制
- 静态访问方法:全局访问点(
getInstance
) - 静态实例指针/引用:保存唯一实例
- 线程安全:使用互斥锁或 C++11 的线程安全静态局部变量
5.使用方式
Singleton& instance = Singleton::getInstance();
6.注意事项
(1)推荐使用 Meyers’ Singleton(方法1),因为:
- 自动线程安全(C++11 标准保证)
- 自动内存管理(无需手动释放)
- 延迟初始化(首次调用时创建)
如果需要继承或更复杂控制,可以考虑智能指针实现
在程序结束时,静态实例会由系统自动销毁
避免在单例析构函数中引用其他可能已被销毁的单例
(1)这两种实现都满足单例模式的三个核心要求:
- 保证唯一实例
- 提供全局访问点
- 防止外部实例化