单例模式用于确保一个类在整个程序运行期间只有一个实例。它适用于需要全局唯一资源管理、配置中心或控制硬件设备的场景,但应避免过度使用以防止代码耦合和测试困难。实现方式包括:1. 懒汉式(线程安全,延迟初始化,需加锁);2. 饿汉式(程序启动时创建,无需加锁);3. meyers' singleton(利用c++++11静态局部变量线程安全,简洁推荐)。此外,需防范反射、序列化及多线程破坏单例,并注意在需要多实例、依赖注入或测试困难时避免使用该模式。游戏引擎中常用于资源、输入和日志管理器。

单例模式,简单来说,就是确保一个类在整个程序运行期间只有一个实例。什么时候用?嗯,当我们需要一个全局唯一的资源管理器、配置中心,或者需要控制某些硬件设备时,单例模式就派上用场了。但要注意,过度使用单例可能会导致代码耦合度过高,测试困难,所以要谨慎。

解决方案:

单例模式的核心在于控制实例的创建,并提供一个全局访问点。在 C++ 中,实现单例模式有几种常见方法,但线程安全是必须要考虑的。
立即学习“C++免费学习笔记(深入)”;
1. 懒汉式(Lazy Initialization) - 线程安全

这是最常见的单例模式实现方式。延迟初始化,只有在第一次使用时才创建实例。为了保证线程安全,需要使用互斥锁。
#include <iostream>
#include <mutex>
class Singleton {
private:
Singleton() {
std::cout << "Singleton created!" << std::endl;
}
~Singleton() {
std::cout << "Singleton destroyed!" << std::endl;
}
static Singleton* instance;
static std::mutex mutex;
public:
static Singleton* getInstance() {
std::lock_guard<std::mutex> lock(mutex); // RAII 风格的锁
if (instance == nullptr) {
instance = new Singleton();
}
return instance;
}
void doSomething() {
std::cout << "Singleton is doing something..." << std::endl;
}
// 禁止拷贝构造和赋值
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
};
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mutex;
int main() {
Singleton* s1 = Singleton::getInstance();
s1->doSomething();
Singleton* s2 = Singleton::getInstance(); // 返回同一个实例
return 0;
}关键点:
instance 是静态成员变量,用于保存唯一的实例。mutex 是互斥锁,用于保证线程安全。getInstance() 是静态方法,用于获取单例实例。使用了 std::lock_guard,确保在离开作用域时自动释放锁,防止死锁。2. 饿汉式(Eager Initialization)
在程序启动时就创建实例,简单粗暴,但线程安全。
#include <iostream>
class Singleton {
private:
Singleton() {
std::cout << "Singleton created!" << std::endl;
}
~Singleton() {
std::cout << "Singleton destroyed!" << std::endl;
}
static Singleton instance; // 直接初始化
public:
static Singleton* getInstance() {
return &instance;
}
void doSomething() {
std::cout << "Singleton is doing something..." << std::endl;
}
// 禁止拷贝构造和赋值
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
};
Singleton Singleton::instance; // 静态成员变量定义
int main() {
Singleton* s1 = Singleton::getInstance();
s1->doSomething();
Singleton* s2 = Singleton::getInstance(); // 返回同一个实例
return 0;
}关键点:
instance 在类定义时直接初始化。3. Meyers' Singleton
利用 C++11 的静态局部变量线程安全特性。这是我个人比较推荐的方式,代码简洁且线程安全。
#include <iostream>
class Singleton {
private:
Singleton() {
std::cout << "Singleton created!" << std::endl;
}
~Singleton() {
std::cout << "Singleton destroyed!" << std::endl;
}
public:
static Singleton& getInstance() {
static Singleton instance; // 静态局部变量,C++11 保证线程安全
return instance;
}
void doSomething() {
std::cout << "Singleton is doing something..." << std::endl;
}
// 禁止拷贝构造和赋值
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
};
int main() {
Singleton& s1 = Singleton::getInstance();
s1.doSomething();
Singleton& s2 = Singleton::getInstance(); // 返回同一个实例
return 0;
}关键点:
instance 是静态局部变量,只在第一次调用 getInstance() 时初始化。单例模式破坏与应对策略
单例模式虽然简单,但也容易被破坏,例如通过反射(虽然 C++ 没有直接的反射机制,但可以通过其他方式模拟)、序列化/反序列化、多线程并发创建等。
Serializable 接口时要特别小心,可以重写 readResolve 方法来返回单例实例。单例模式与其他设计模式的比较
单例模式经常与工厂模式、建造者模式等一起使用。
何时避免使用单例模式
单例模式并非银弹,过度使用会导致代码耦合度过高,测试困难。以下情况应避免使用单例模式:
单例模式在游戏引擎中的应用
在游戏引擎中,单例模式常用于管理全局资源,例如:
这些管理器通常只需要一个实例,因此使用单例模式非常合适。
以上就是什么时候应该使用C++单例模式 线程安全实现与适用场景分析的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号