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

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及以上版本中,推荐使用局部静态变量的实现方式,它简洁、安全且高效。对于更复杂的需求,可以考虑模板化单例或依赖注入等高级技术。

相关文章:

  • c++面向对象基础学习笔记
  • dfs bfs 最短路 最小生成树 出错原因
  • 第 7 章:综合回顾与性能优化
  • 封装WPF中列表控件的剪贴板操作(附源码)
  • Flask框架全方位深度解析
  • 告别繁琐操作,一键批量发布!
  • Docker安装Nginx(最完整的安装方式)
  • 2025年5月网工基础知识
  • Linux iSCSI存储共享实验指南
  • SpringMVC(结合源码浅析工作流程)
  • 一条SQL语句的旅程:解析、优化与执行全过程研究
  • 【论文精读】2023 AAAI--FastRealVSR现实世界视频超分辨率(RealWorld VSR)
  • Flutter遇到的问题
  • 数据结构(5)线性表-栈
  • Flutter - 国际化
  • 【JVM 02-JVM内存结构之-程序计数器】
  • 线程池介绍,分类,实现(工作原理,核心组成,拒绝策略),固态线程池的实现+详细解释(支持超时取消机制和不同的拒绝策略)
  • OBS 玩转你直播录视频
  • 【SSL部署与优化​】​​OCSP Stapling配置指南:减少证书验证延迟​​
  • ten-vad:低延迟、轻量化且高性能的流式语音活动检测系统
  • 网页设计介绍说明/北海百度seo
  • 济南网站优化网站/网店推广有哪些方法
  • 网站建设国内排行/什么平台发广告最有效
  • 深圳做兼职的网站/百度推广时间段在哪里设置
  • 北海市住建局官方网站/全网推广软件
  • 广州网站开发技术/网站营销