单例模式-创建型

一、单例模式

1.1、核心思想

保证一个类只有一个实例,并提供一个全局访问点

1.2、为什么要用单例模式?

问题场景:

假设有一个配置管理器,如果程序中到处都能随意创建它的实例:

cpp 复制代码
// 在A文件中
ConfigManager* config1 = new ConfigManager();
config1->setValue("theme", "dark");

// 在B文件中  
ConfigManager* config2 = new ConfigManager();
string theme = config2->getValue("theme"); // 可能得到错误的值!

配置信息不一致,内存浪费。

解决方案:单例模式

cpp 复制代码
// 在A文件中
ConfigManager* config1 = ConfigManager::getInstance();
config1->setValue("theme", "dark");

// 在B文件中
ConfigManager* config2 = ConfigManager::getInstance(); 
string theme = config2->getValue("theme"); // 保证是 "dark"
// config1 和 config2 实际上是同一个实例!

1.3、单例模式实现

  1. 基础懒汉式(线程不安全)
cpp 复制代码
class Singleton {
private:
    static Singleton* instance;  // 静态私有成员
    Singleton() {}  // 私有构造函数,防止外部创建实例
    Singleton(const Singleton&) = delete;  // 禁止拷贝
    Singleton& operator=(const Singleton&) = delete;  // 禁止赋值

public:
    static Singleton* getInstance() {
        if (instance == nullptr) {
            instance = new Singleton();
        }
        return instance;
    }
    
    void doSomething() {
        cout << "单例对象在工作..." << endl;
    }
};

// 静态成员初始化
Singleton* Singleton::instance = nullptr;
  1. 懒汉式(线程安全,但不高效)
cpp 复制代码
#include <mutex>

class Singleton {
private:
    static Singleton* instance;
    static std::mutex mtx;  // 互斥锁
    
    Singleton() { 
        cout << "Singleton 实例被创建!" << endl; 
    }
    ~Singleton() = default;
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;

public:
    static Singleton* getInstance() {
        if (instance == nullptr) {  // 第一次检查,避免不必要的锁
            std::lock_guard<std::mutex> lock(mtx);  // 加锁
            if (instance == nullptr) {  // 第二次检查,确保线程安全
                instance = new Singleton();
            }
        }
        return instance;
    }
    
    void doSomething() {
        cout << "单例对象在工作..." << endl;
    }
};

// 静态成员初始化
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;

利用互斥锁进行线程安全控制,但每次调用getInstance()时都需要加锁解锁,效率较低。

  1. C++11 静态局部变量(线程安全,高效)
cpp 复制代码
class Singleton {
private:
    Singleton() = default;
    ~Singleton() = default;
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;

public:
    static Singleton& getInstance() {
        static Singleton instance;  // C++11保证这是线程安全的
        return instance;
    }
    
    void doSomething() {
        cout << "单例对象在工作..." << endl;
    }
};

线程安全:C++11标准保证

二、实战案例

获取系统时间:

很明确这是全局且唯一的,那么可以使用单例模式。

cpp 复制代码
class SystemTime
{
    public:
        static SystemTime* getInstance()
        {
            static SystemTime instance;
            return &instance;
        }
        ~ SystemTime(){}
        DateTime getCurrentTime()const{ return DateTime::now(); }
    private:
        SystemTime(){}
        SystemTime(const SystemTime&)=delete;
        SystemTime& operator=(const SystemTime&)=delete;
};

// 使用
auto currentTime = SystemTime::getInstance()->getCurrentTime();

不过实际应用中,时间一般都包含在某个组件中,比如日志,游戏存档等,所以一般不会单独用一个单例类来管理时间。

三、总结

3.1、单例模式优缺点

优点 缺点
严格控制实例数量 全局状态,可能被任意修改
全局访问点,方便使用 不利于单元测试
节约系统资源 违反单一职责原则(既要管理业务,也要管理生命周期)
懒加载,提高性能 隐藏了依赖关系

3.2、适用场景

  1. 日志系统:整个程序共享一个日志实例
  2. 数据库连接池:只需要一个连接池管理器
  3. 线程池
  4. 游戏存档系统
    ***Tips:***没有完美的设计模式,只有更适合该场景的模式;在使用单例模式,需权衡利弊
相关推荐
坤坤子吖2 小时前
Linux网络编程:TCP服务器的多进程与多线程实现
linux·服务器·开发语言·网络·c++·笔记·学习
一晌小贪欢2 小时前
Python基础:第 09 篇 · while 循环:重复直到不满足
开发语言·c++·python·数据可视化·面向对象·python办公
xiaoye-duck3 小时前
《C++ 项目:手写大模型接入 SDK》LLMManager架构设计与实现
开发语言·网络·c++·语言模型
一条大祥脚3 小时前
CuTe 与 CuTe DSL:从 C++ 模板元编程到 Python DSL 的 GPU 编程演进
开发语言·c++·python·cutlass·cute·cute dsl
·present·3 小时前
CSAPP(lecture 13_02 Linking)
c语言·c++
旖旎夜光4 小时前
【C++ 基础入门】C++ 多态(上):虚函数、重写、override/final 与抽象类
开发语言·c++·笔记·学习
青少儿编程课堂6 小时前
蓝桥杯青少组图形化 STEMA 省考(报名倒计时·11/22开考)+ 全国青少年信息素养大赛 2026—2027赛季 + 电子学会图形化考级:校园华容道大闯关
c++·python·算法·bfs·信息学竞赛
白杨尚青6 小时前
C++进阶篇(五):红黑树——四条规则、三种插入情况与旋转变色
开发语言·数据结构·c++·stl·红黑树·平衡二叉树
旖旎夜光7 小时前
【C++ 基础入门】C++ 继承(上):概念、切片、隐藏、默认成员函数与友元
c++·笔记·学习
apcipot_rain8 小时前
C++转Java日记(05)
java·开发语言·c++