当前位置: 首页 > ops >正文

C++单例模式详解

单例模式(Singleton Pattern)是设计模式中最简单但也是最常用的一种创建型模式,它确保一个类只有一个实例,并提供一个全局访问点。下面我将从多个维度全面解析C++中的单例模式实现。

核心要点:只初始化一次,需要有一个静态的getinstance接口 ,使用的时候不需要对象直接通过域名使用

一、基础实现

1. 经典实现(非线程安全)

class Singleton {
private:static Singleton* instance;  // 静态成员变量Singleton() {}              // 私有构造函数~Singleton() {}             // 私有析构函数Singleton(const Singleton&) = delete;            // 禁用拷贝构造Singleton& operator=(const Singleton&) = delete; // 禁用赋值操作符public:static Singleton* getInstance() {if (instance == nullptr) {instance = new Singleton();}return instance;}
};// 静态成员初始化
Singleton* Singleton::instance = nullptr;

 问题:非线程安全,多线程环境下可能创建多个实例

虽然静态函数还是同一个,但是多次创建会导致内存泄漏(前面创建的实例的静态函数的指针是空的),与及其他多个实例的非静态成员函数同时和一个静态函数交互会导致混乱。

二、线程安全实现

2.1 加锁实现(双重检查锁定)

#include <mutex>class Singleton {
private:static Singleton* instance;static std::mutex mtx;Singleton() {}~Singleton() {}public:static Singleton* getInstance() {if (instance == nullptr) {  // 第一次检查std::lock_guard<std::mutex> lock(mtx);if (instance == nullptr) {  // 第二次检查instance = new Singleton();}}return instance;}
};// 静态成员初始化
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;

优点:线程安全且效率较高
注意:C++11前可能需要volatile关键字防止指令重排

2.2 C++11局部静态变量实现(最推荐)

class Singleton {
private:Singleton() {}~Singleton() {}public:static Singleton& getInstance() {static Singleton instance;  // C++11保证静态局部变量初始化线程安全return instance;}
};

优点

  • 线程安全(C++11标准保证)

  • 自动析构(程序结束时)

  • 实现简单

  • 延迟初始化(首次调用时构造)

三、高级主题

3.1 模板化单例

template<typename T>
class Singleton {
protected:Singleton() = default;~Singleton() = default;public:static T& getInstance() {static T instance;return instance;}Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;
};// 使用方式
class MyClass : public Singleton<MyClass> {friend class Singleton<MyClass>;
private:MyClass() {}  // 构造函数必须私有
};

3.2 单例的销毁时机控制 

class Singleton {
private:Singleton() {}~Singleton() {}static Singleton& getRawInstance() {static Singleton instance;return instance;}public:static Singleton& getInstance() {return getRawInstance();}// 手动销毁接口(谨慎使用)static void destroyInstance() {// 实际无法真正销毁,但可以重置状态}
};

 3.3 多环境适配单例

 

#ifdef _WIN32#include <windows.h>
#else#include <pthread.h>
#endifclass CrossPlatformSingleton {
private:static CrossPlatformSingleton* instance;#ifdef _WIN32static CRITICAL_SECTION cs;#elsestatic pthread_mutex_t mutex;#endifCrossPlatformSingleton() {#ifdef _WIN32InitializeCriticalSection(&cs);#elsepthread_mutex_init(&mutex, nullptr);#endif}public:static CrossPlatformSingleton* getInstance() {if (instance == nullptr) {#ifdef _WIN32EnterCriticalSection(&cs);#elsepthread_mutex_lock(&mutex);#endifif (instance == nullptr) {instance = new CrossPlatformSingleton();}#ifdef _WIN32LeaveCriticalSection(&cs);#elsepthread_mutex_unlock(&mutex);#endif}return instance;}
};

四、单例模式的变体

4.1 多例模式(限制实例数量)

class Multiton {
private:static const int MAX_INSTANCES = 3;static std::array<Multiton*, MAX_INSTANCES> instances;static std::mutex mtx;static int nextIndex;Multiton() {}public:static Multiton* getInstance() {std::lock_guard<std::mutex> lock(mtx);if (nextIndex < MAX_INSTANCES) {instances[nextIndex] = new Multiton();return instances[nextIndex++];}return instances[rand() % MAX_INSTANCES];  // 随机返回一个实例}
};

4.2 线程局部单例(每个线程一个实例)

class ThreadLocalSingleton {
private:ThreadLocalSingleton() {}public:static ThreadLocalSingleton& getInstance() {thread_local ThreadLocalSingleton instance;return instance;}
};

五、单例模式的优缺点

优点:

  1. 严格控制实例数量

  2. 全局访问点方便管理

  3. 延迟初始化节省资源

  4. 避免频繁创建销毁对象

缺点:

  1. 违反单一职责原则(同时控制生命周期和业务逻辑)

  2. 难以扩展(需要修改代码而非配置)

  3. 隐藏类之间的依赖关系

  4. 对单元测试不友好(难以mock)

  5. 在多线程环境中需要特别注意线程安全

六、使用场景

  1. 配置管理:全局配置只需要一个实例

  2. 日志系统:整个应用共享一个日志管理器

  3. 设备驱动:如打印机假脱机系统

  4. 缓存系统:全局内存缓存

  5. 线程池:通常只需要一个线程池实例

七、现代C++最佳实践

  1. 优先使用局部静态变量实现(C++11及以上)

  2. 考虑使用std::call_once作为替代方案

class Singleton {
private:static std::once_flag onceFlag;static Singleton* instance;Singleton() {}public:static Singleton& getInstance() {std::call_once(onceFlag, []() {instance = new Singleton();});return *instance;}
};

3.对于需要参数的单例,可以使用以下模式: 

class Config {
private:std::string configPath;Config(const std::string& path) : configPath(path) {}public:static Config& getInstance(const std::string& path = "") {static Config instance(path.empty() ? "default.conf" : path);return instance;}
};

 

八、单例模式与依赖注入

在现代软件设计中,依赖注入(DI)框架常被用来替代单例模式,因为它能更好地解耦和测试:

// 使用依赖注入框架(如Google Fruit)
fruit::Injector<MyService> injector(getMyServiceComponent);
MyService* service = injector.get<MyService*>();

这种方式的优点是可以更容易地替换实现和进行单元测试。

总结

C++中的单例模式实现需要考虑线程安全、生命周期管理、可测试性等多方面因素。在C++11及以上版本中,推荐使用局部静态变量的实现方式,它简洁、安全且高效。对于更复杂的需求,可以考虑模板化单例或依赖注入等高级技术。

http://www.xdnf.cn/news/8273.html

相关文章:

  • 前端(小程序)学习笔记(CLASS 2):WXML模板语法与WXSS模板样式
  • 光电耦合器与数字容隔离器的“光速对话”
  • Java设计模式:探索编程背后的哲学
  • python定时删除指定索引
  • 谷歌浏览器调试python pygui程序
  • 国产化Word处理控件Spire.Doc教程:使用 Python 创建 Word 文档的详细指南
  • 企业级云原生爬虫架构与智能优化
  • LET 2025盛大开幕!数智工厂×智慧物流×机器人,一展get创新科技
  • VSCode 插件 GitLens 破解方法
  • 线程池介绍,分类,实现(工作原理,核心组成,拒绝策略),固态线程池的实现+详细解释(支持超时取消机制和不同的拒绝策略)
  • [性能优化] 数据库连接池(Connection Pooling)原理及其在Java/Python应用中的配置
  • 大模型高效微调方法综述:P-Tuning软提示与lora低秩微调附案例代码详解
  • 在 ABP VNext 中集成 OpenCvSharp:构建高可用图像灰度、压缩与格式转换服务
  • 自制操作系统day10叠加处理
  • 数据库系统概论(九)SQL连接查询语言超详细讲解(附带例题,表格详细讲解对比带你一步步掌握)
  • MCP 服务与 Agent 协同架构的理论基石:从分布式智能到生态化协作
  • OSI 深度安全防御体系架构深度剖析
  • Java转Go日记(五十六):gin 渲染
  • 可视化大屏实现全屏或非全屏
  • iOS使用Metal对采集视频进行渲染
  • 【YOLO】Docker搭建镜像+运行容器
  • 如何制作令人印象深刻的UI设计?
  • HTTP 协议详解
  • 全金属工业防爆散热风扇风压与散热效果的关系
  • 无人机飞行间隔安全智能评估、安全风险评估
  • 单片机——实现交通信号灯管理
  • 【mindspore系列】- 算子源码分析
  • 超越感官的实相:声、光、气味的科学与哲学探微
  • Azure 公有云基础架构与核心服务:从基础到实践指南
  • C++——STL——封装红黑树实现mymap与myset