C++ 单例模式超详细讲解

C++ 单例模式超详细讲解

C++ 单例模式(Singleton)超详细讲解

我会用最通俗、最完整 的方式,把单例模式的背景、意义、用法、优势、实现、坑点一次性讲透,新手也能完全看懂。

一、什么是单例模式?

单例模式 = 一个类,在整个程序运行期间,只能创建唯一一个对象,不能创建第二个。

简单说:

  • 这个类永远只有一个实例

  • 无论你在代码哪里用,拿到的都是同一个对象

  • 禁止外部手动 new、禁止拷贝、禁止赋值

二、背景:为什么会出现单例模式?

在程序里,有些对象天生就应该只有一个,如果允许多个实例,会出大问题:

常见场景:

  • 日志管理器(多个日志对象会导致日志混乱、重复写入)

  • 配置管理器(全局配置只应该读一份)

  • 数据库连接池(重复创建连接浪费资源)

  • 线程池、缓存管理器、打印机管理器、游戏引擎管理器

  • 全局工具类(只需要一份,不需要反复创建)

如果不控制实例数量:

  • 资源浪费

  • 数据不一致

  • 逻辑错误

  • 程序崩溃

于是单例模式 就诞生了,专门解决:
全局唯一实例 + 统一访问点

三、单例模式的核心意义

一句话总结:
保证一个类在程序生命周期内有且仅有一个实例,并提供一个全局访问点。

它解决两个核心问题:

  1. 全局唯一:避免重复创建、资源冲突

  2. 全局可访问:不用到处传递对象,随时能获取

四、单例模式的优势(为什么要用?)

1. 严格控制唯一实例

从语法层面禁止创建多个对象,从根源避免错误。

2. 节约系统资源

像数据库连接、日志、配置文件,只初始化一次,不重复消耗。

3. 全局统一访问

任何地方直接获取实例,不用层层传参,代码更简洁。

4. 延迟初始化(懒汉模式)

用到时才创建,不浪费启动时间。

5. 避免全局变量的缺点

全局变量:

  • 没有封装

  • 可以被随意修改

  • 没有控制构造 / 析构

单例:

  • 完全封装

  • 可控生命周期

  • 线程安全可控制

  • 更优雅、更安全

五、单例模式的 4 个关键规则(必须记住)

要写一个正确的 C++ 单例,必须满足:

  1. 构造函数私有化 :禁止外部 new

  2. 删除拷贝构造 + 赋值运算符:禁止拷贝、赋值

  3. 提供一个静态获取实例函数 :getInstance\(\)

  4. 唯一实例存储在静态成员变量

六、C++ 单例的两种经典实现

1. 饿汉模式(Eager)

程序一启动就创建实例

  • 优点:简单、天生线程安全

  • 缺点:启动稍慢

cpp 复制代码
class Singleton {
public:
    // 禁用拷贝和赋值
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;

    // 全局访问点
    static Singleton& getInstance() {
        return instance;
    }

    // 测试函数
    void doSomething() {
        // ...
    }

private:
    // 构造函数私有化
    Singleton() {}

    // 程序启动时就创建唯一实例
    static Singleton instance;
};

// 静态成员初始化
Singleton Singleton::instance;

使用方式:

cpp 复制代码
Singleton& obj = Singleton::getInstance();
obj.doSomething();

2. 懒汉模式(Lazy)------ 最常用

用到时才创建实例(延迟初始化)

C++11 之后最推荐、最简单、线程安全的写法:

cpp 复制代码
class Singleton {
public:
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;

    static Singleton& getInstance() {
        // C++11 保证 static 内部变量线程安全
        static Singleton instance;
        return instance;
    }

    void doSomething() {}

private:
    Singleton() {}
};

✅ 这是现代 C++ 最优单例实现

  • 线程安全

  • 延迟加载

  • 自动销毁

  • 代码极简

七、单例模式怎么用?

cpp 复制代码
// 获取单例对象
auto& logger = Singleton::getInstance();

// 使用成员函数
logger.doSomething();

// 永远是同一个对象
auto& logger2 = Singleton::getInstance();
// logger 和 logger2 是同一个实例

八、单例模式的缺点

没有任何设计模式完美,单例也有坑:

  1. 过度使用会造成代码耦合

  2. 难以单元测试(因为全局唯一,无法 mock)

  3. 多线程下要注意线程安全

  4. 生命周期不好控制(程序结束才销毁)

  5. 隐藏依赖关系(代码看不到参数传递)

结论:单例很好,但不要滥用。

九、单例模式适用场景

你可以放心用单例的情况:

  • 日志系统

  • 配置管理

  • 数据库连接池

  • 缓存

  • 线程池

  • 全局管理器(引擎、UI、音频等)


总结(超精简版)

  1. 单例 = 一个类只能有一个对象

  2. 目的:全局唯一、节约资源、统一访问

  3. 核心规则:私有构造 + 禁用拷贝 + 静态访问点

  4. 最佳实现:C++11 静态局部变量(懒汉、线程安全)

  5. 优势:安全、简洁、无资源浪费

  6. 缺点:不能滥用,会造成耦合

(注:文档部分内容可能由 AI 生成)

相关推荐
波力海苔夹心脆675几秒前
C# WPF 资源字典详解:ResourceDictionary、MergedDictionaries 与自定义控件案例
开发语言·c#·wpf·入门教程·resource·资源字典
不会算法的笨小孩22 分钟前
异常的使用以及会出现的问题
开发语言·c++·c++11·异常
Hhy_11073 小时前
《C++深度解构06》手撕 string —— 从底层内存管理到深浅拷贝彻底吃透
c语言·开发语言·c++·学习·visual studio
starzy19903 小时前
深入理解Scala函数定义:从方法到函数的类型跨越
开发语言·scala
starzy19903 小时前
深入理解Scala递归函数:从栈溢出到尾调用优化
开发语言·scala
三*一3 小时前
Mapbox‑GL JS 多边形折点编辑工具:实现原理、功能拆解与踩坑总结
开发语言·javascript·ecmascript
青少儿编程课堂3 小时前
蓝桥杯青少组图形化省考报名倒计时·全国青少年信息素养大赛·电子学会图形化考级:校园黑白棋人机对战解析
c++·python·算法·bfs·信息学竞赛
YSL0701243 小时前
C++基础
开发语言·c++
若亦_3 小时前
Java中关于this的三种用法
java·开发语言·intellij-idea
2601_968793144 小时前
Python Requests 轻量自动化:无需浏览器,实现真人级账号浏览模拟
开发语言·python·自动化