C++:单例模式

1.什么是单例

单,就是单个的意思,例,就是实例化。所谓单例模式,指的就是程序运行期间,在全局范围内,有且只有一个类的实例化存在。它其实是一种设计思想,和语言没有关系。只要按照这种设计思想,哪种语言都可以实现自己的单例模式。

单例模式用的最多的场景就是工具类,节省资源,全局调用。

而为了保证只有一个实例存在,在设计单例时候,就要将类的构造函数私有化,防止外部创建。同时将类的拷贝构造函数和赋值操作符删除,防止复制和赋值。

单例模式的实现方式有三种。C++11之前,主要通过饿汉式或懒汉式实现,C++11之后,通过静态局部变量实现。静态局部变量这种方式,既简洁又高效。

2.饿汉式

饿汉式是通过类的静态成员变量实现的。因为静态成员变量的初始化,是在main函数加载前完成的,所以它天然是线程安全的。

代码举例如下:

头文件:EagerSingleton.h

cpp 复制代码
//EagerSingleton.h

#pragma once

#include <iostream>
using namespace std;

class EagerSingleton
{
public:
    static EagerSingleton& getInstance() {
        return instance;
    }

    void doSomething() {
        cout << "EagerSingleton 做事..." << endl;
        
    }

private:
    // 私有构造函数
    EagerSingleton() { cout << "EagerSingleton 构造函数" << endl; }

    // 拷贝构造和赋值操作符删除,防止复制
    EagerSingleton(const EagerSingleton&) = delete;
    EagerSingleton& operator=(const EagerSingleton&) = delete;

    // 静态实例在类外定义,程序启动时即初始化
    static EagerSingleton instance;

};

源文件:EagerSingleton.cpp

cpp 复制代码
#include "EagerSingleton.h"


EagerSingleton EagerSingleton::instance;

调用方式:

cpp 复制代码
EagerSingleton& s1 = EagerSingleton::getInstance()

3.懒汉式

懒汉式又可分为两种,一种是简单版本,一种是双重检测+锁版本。他俩唯一区别就是第一个不是线程安全,第二个是线程安全的。

简单版本代码举例

头文件:LazySingleton.h

cpp 复制代码
#pragma once
#include <iostream>
using namespace std;

class LazySingleton
{
public:
    static LazySingleton* getInstance() {
        if (instance == nullptr) {   // 多线程下可能同时进入
            instance = new LazySingleton();
        }
        return instance;
    }

    void doSomething() {
        cout << "LazySingleton 做事..." << endl;

    }

private:
    // 私有构造函数
    LazySingleton() { cout << "LazySingleton 构造函数" << endl; }

    // 拷贝构造和赋值操作符删除,防止复制
    LazySingleton(const LazySingleton&) = delete;
    LazySingleton& operator=(const LazySingleton&) = delete;

    // 静态实例在类外定义,程序启动时即初始化
    static LazySingleton* instance;
};

源文件:LazySingleton.cpp

cpp 复制代码
#include "LazySingleton.h"

LazySingleton* LazySingleton::instance = nullptr;

双重检测+锁版本代码举例

头文件:LazySingletonDCL.h

cpp 复制代码
#pragma once

#include <iostream>
#include <mutex>
using namespace std;

class LazySingletonDCL
{
public:
    static LazySingletonDCL* getInstance() {
        // 第一层判断:避免每次加锁损耗性能
        if (instance == nullptr) {
            lock_guard<mutex> lock(mtx);
            // 第二层判断:防止多线程等待锁后重复创建
            if (instance == nullptr) {
                instance = new LazySingletonDCL();
            }
        }
        return instance;
    }

    void doSomething() {
        cout << "LazySingletonDCL 做事..." << endl;

    }

private:
    // 私有构造函数
    LazySingletonDCL() { cout << "LazySingletonDCL 构造函数" << endl; }

    // 拷贝构造和赋值操作符删除,防止复制
    LazySingletonDCL(const LazySingletonDCL&) = delete;
    LazySingletonDCL& operator=(const LazySingletonDCL&) = delete;

    // 静态实例在类外定义,程序启动时即初始化
    static LazySingletonDCL* instance;
    static mutex mtx;
};

源文件:LazySingletonDCL.cpp

cpp 复制代码
#include "LazySingletonDCL.h"

LazySingletonDCL* LazySingletonDCL::instance = nullptr;
mutex LazySingletonDCL::mtx;

调用方式

cpp 复制代码
LazySingleton* s1 = LazySingleton::getInstance();

4.静态局部变量方式

这种方式是C++11后才能使用,是目前单例的最优解。

代码举例如下:

头文件:SingletonMeyer.h

cpp 复制代码
#pragma once

#include <iostream>
using namespace std;

class SingletonMeyer
{
public:
    static SingletonMeyer& getInstance() {
        // 第一次调用才创建,线程安全
        static SingletonMeyer instance;
        return instance;
    }

    void doSomething() {
        cout << "SingletonMeyer 做事..." << endl;

    }

private:
    // 私有构造函数
    SingletonMeyer() { cout << "SingletonMeyer 构造函数" << endl; }

    // 拷贝构造和赋值操作符删除,防止复制
    SingletonMeyer(const SingletonMeyer&) = delete;
    SingletonMeyer& operator=(const SingletonMeyer&) = delete;


};

源文件:SingletonMeyer.cpp

cpp 复制代码
#include "SingletonMeyer.h"

//相关函数也可以在头文件中声明,在这里实现。

调用方式

cpp 复制代码
SingletonMeyer& ins = SingletonMeyer::getInstance();
ins.doSomething();
相关推荐
汉克老师4 小时前
GESP2026年9月认证C++六级( 第三部分编程题(1、数组划分))精讲
c++·gesp·小学生·学c++编程
千里码aicood5 小时前
基于PLC与机器视觉的智能分拣控制系统设计
c++·自动化·plc
漂流瓶jz5 小时前
UVA-1442 洞穴 题解答案代码 算法竞赛入门经典第二版
c++·算法·题解·aoapc·算法竞赛入门经典·uva
朽棘不雕5 小时前
进一步了解模板
c++
汉克老师8 小时前
CSP-J 2026 初赛试题解析(第一部分:选择题(8-15))精讲
c++·csp-j·小学生·学c++编程
wabs6669 小时前
关于二叉树【力扣572.另一棵树的子树的思考】
数据结构·c++·算法·leetcode·二叉树
风合星语10 小时前
2026 ROS 2 Lyrical C++ 入门(五):Action 实战——任务反馈、取消与超时处理
c++·机器人·ros2·异步编程·lyrical
91刘仁德10 小时前
C++ 继承和多态 设计模式
c语言·c++·笔记
库玛西11 小时前
哈夫曼树与前缀编码:数据压缩的贪心核心
c语言·c++·笔记·考研
别动我齐刘海11 小时前
ROS2 Jazzy + C++ 实战路线——进阶学习3
c++·人工智能·vscode·python·算法·机器学习·机器人