C++单例模式 : 懒汉模式 与 饿汉模式

article/2025/9/22 2:00:11

 单例模式:

        只能有一个实例,有懒汉和饿汉区分,实现核心思想:

        1.构造函数私有化

        2.使用静态函数作为接口来获取类对象

1、懒汉模式:

        由调用者实例,多线程情况下会存在线程安全问题,需要加互斥锁进行防护

2、饿汉模式:

        没有人为实例对象时,就把对象给实例好,当需要使用时只要通过接口函数直接获取对象

注意:

     饿汉模式new的对象,需要人为处理,否则会导致内存泄漏,可以使用智能指针进行管理,或者写个静态的类中类,让类中类进行析构释放

代码示例:

饿汉模式

//饿汉模式,没有线程安全问题,无需加锁
class singleHungry
{
private:int dataA;int dataB;
private://构造函数私有化singleHungry(int a, int b):dataA(a),dataB(b){} //禁用默认拷贝构造、赋值运算符函数singleHungry(const singleHungry& s) = delete;singleHungry& operator= (const singleHungry& s) = delete;
public:~singleHungry(){}static singleHungry s_instacne;static singleHungry& getInstacne();//业务逻辑int getAddResult(){int result = dataA + dataB;cout<<"add result = "<<result<<endl;return result;}
};//静态变量需要在类外进行初始化,由于对象是静态变量,存储在静态存储区,无需人为回收,进程结束自动回收内存
singleHungry singleHungry::s_instacne(1,2);
singleHungry& singleHungry::getInstacne()
{return s_instacne;
}

懒汉模式


//懒汉模式,存在线程安全问题,需要加锁
class singleLazy
{
private:int dataA;int dataB;
private://构造函数私有化singleLazy(int a, int b):dataA(a),dataB(b){}//禁用默认拷贝构造、赋值运算符函数singleLazy(const singleLazy& s) = delete;singleLazy& operator= (const singleLazy& s) = delete;
public:~singleLazy(){}//互斥锁解决线程安全问题static mutex s_mute; //智能指针管理对象,解决内存泄漏问题static shared_ptr<singleLazy> s_instance;static shared_ptr<singleLazy> createInstance();//业务逻辑int getSubResult(){int result = dataA - dataB;cout<<"sub result = "<<result<<endl;return result;}
};//静态变量需要在类外进行初始化
mutex singleLazy::s_mute;
shared_ptr<singleLazy> singleLazy::s_instance = nullptr;
shared_ptr<singleLazy> singleLazy::createInstance()
{if (nullptr == s_instance) //未构造{s_mute.lock();cout<<"first structure"<<endl;s_instance = shared_ptr<singleLazy>(new singleLazy(3,4));s_mute.unlock();}else{cout<<"has structured"<<endl;}return s_instance;
}

完整代码如下:

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

//饿汉模式,没有线程安全问题,无需加锁
class singleHungry
{
private:
    int dataA;
    int dataB;
private:
    //构造函数私有化
    singleHungry(int a, int b):dataA(a),dataB(b){} 

    //禁用默认拷贝构造、赋值运算符函数
    singleHungry(const singleHungry& s) = delete;
    singleHungry& operator= (const singleHungry& s) = delete;
public:
    ~singleHungry(){}
    static singleHungry s_instacne;
    static singleHungry& getInstacne();

    //业务逻辑
    int getAddResult()
    {
        int result = dataA + dataB;
        cout<<"add result = "<<result<<endl;
        return result;
    }
};

//静态变量需要在类外进行初始化,由于对象是静态变量,存储在静态存储区,无需人为回收,进程结束自动回收内存
singleHungry singleHungry::s_instacne(1,2);
singleHungry& singleHungry::getInstacne()
{
    return s_instacne;
}


//懒汉模式,存在线程安全问题,需要加锁
class singleLazy
{
private:
    int dataA;
    int dataB;
private:
    //构造函数私有化
    singleLazy(int a, int b):dataA(a),dataB(b){}
    //禁用默认拷贝构造、赋值运算符函数
    singleLazy(const singleLazy& s) = delete;
    singleLazy& operator= (const singleLazy& s) = delete;
public:
    ~singleLazy(){}
    //互斥锁解决线程安全问题
    static mutex s_mute; 
    //智能指针管理对象,解决内存泄漏问题
    static shared_ptr<singleLazy> s_instance;
    static shared_ptr<singleLazy> createInstance();

    //业务逻辑
    int getSubResult()
    {
        int result = dataA - dataB;
        cout<<"sub result = "<<result<<endl;
        return result;
    }
};

//静态变量需要在类外进行初始化
mutex singleLazy::s_mute;
shared_ptr<singleLazy> singleLazy::s_instance = nullptr;
shared_ptr<singleLazy> singleLazy::createInstance()
{
    if (nullptr == s_instance) //未构造
    {
        s_mute.lock();
        cout<<"first structure"<<endl;
        s_instance = shared_ptr<singleLazy>(new singleLazy(3,4));
        s_mute.unlock();
    }
    else
    {
        cout<<"has structured"<<endl;
    }

    return s_instance;
}


//客户端
int main()
{
    //饿汉模式
    singleHungry::getInstacne().getAddResult();

    //懒汉模式
    singleLazy::createInstance()->getSubResult();
    singleLazy::createInstance()->getSubResult();
    return 0;
}

【采用单例模式动机、原因】
      对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。如在Windows中就只能打开一个任务管理器。如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。因此有时确保系统中某个对象的唯一性即一个类只能有一个实例非常重要。
      如何保证一个类只有一个实例并且这个实例易于被访问呢?定义一个全局变量可以确保对象随时都可以被访问,但不能防止我们实例化多个对象。一个更好的解决办法是让类自身负责保存它的唯一实例。这个类可以保证没有其他实例被创建,并且它可以提供一个访问该实例的方法。这就是单例模式的模式动机。


http://chatgpt.dhexx.cn/article/A4hQ1f4B.shtml

相关文章

单例模式的创建(饿汉模式懒汉模式)

&#x1f388;专栏链接:多线程相关知识详解 目录 一.什么是单例模式 二.用static来创建单例模式 三.饿汉模式与懒汉模式 四.饿汉模式与懒汉模式的线程安全问题 五.New引发的指令重排序问题 六.小结 一.什么是单例模式 单例模式就是指某个类有且只有一个实例(instance…

单例模式:懒汉模式

所谓“懒汉式”与“饿汉式”的区别&#xff0c;是在与建立单例对象的时间的不同。 “懒汉式”是在你真正用到的时候才去建这个单例对象“饿汉式是在类创建的同时就已经创建好一个静态的对象&#xff0c;不管你用的用不上&#xff0c;一开始就建立这个单例对象 代码实现&#x…

java 单例模式 之懒汉模式

单例模式&#xff1a;一个类&#xff0c;始终仅仅对外提供自己的一个实例&#xff0c;这样的设计方案&#xff0c;就称单例模式。 懒汉模式&#xff1a; 构造函数私有 声明私有的本类静态实例 定义静态的方法&#xff0c;在方法中创建本类实例&#xff0c;并返回该实例 pu…

单例模式饿汉模式与懒汉模式

目录 1.什么是单例模式 2.为什么需要单例模式&#xff1f; 3.如何实现单例模式 3.1饿汉方式 3.2懒汉模式 1.什么是单例模式 单例模式是一种设计模式&#xff0c;单例模式能保证某个类在程序中只存在唯一一份实例, 而不会创建出多个实例。单例模式的具体实现又分为饿汉模式…

关于Java中单例模式(饿汉模式和懒汉模式)的简析

目录 一.什么是单例模式 二.饿汉模式和懒汉模式 饿汉模式 代码 懒汉模式 代码 关于多线程安全的问题 如何解决懒汉模式多线程安全问题 双if判断 一.什么是单例模式 简单来说,就是我们在程序中通过代码进行限制,在该程序中 只能创建一个对象 二.饿汉模式和懒汉模式 …

java设计模式之单例模式|单例模式之饿汉模式、懒汉模式、枚举方式|最详细的6种懒汉模式详解

目录 一、单例模式 二、饿汉模式和懒汉模式 1、饿汉模式&#xff0c;线程安全 2、懒汉模式 懒汉模式1&#xff0c;线程不安全&#xff08;不常用&#xff09; 懒汉模式2&#xff0c;线程安全&#xff08;不常用&#xff09; 懒汉模式3&#xff0c;线程安全&#xff0c;双…

全志F1C100s主线linux入坑记录 (10)调试串口更改

调试串口更改 百度网站 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 调试串口更改前言uboot 修改一、修改设备树二、修改文件3. 修改内核传递参数 内核修改参考 前言 未完成版本 未完成版本 未完成版本 未完成…

f1c100s 调试问题汇总

问题 usb无法识别 windows显示无法识别的usb设备 解决&#xff1a; 卸载设备&#xff0c;插拔一下&#xff0c;就可以识别了&#xff0c;之后就会自动安装驱动。 umount失败 fuser ./d2 可以显示出当前哪个程序在使用磁盘上的某个文件、挂载点、甚至网络端口&#xff0c;并…

【f1c200s/f1c100s】FT5426触摸屏驱动适配

【f1c200s/f1c100s】FT5426触摸屏驱动适配 前言设备树配置IIC控制器FT5426设备树配置 内核配置结果 前言 嵌入式linux下的触摸屏驱动是基于input子系统的&#xff0c;当触摸发生时&#xff0c;内核上报触摸事件至用户层。我使用的显示屏是正点原子的7寸RGB接口显示屏&#xff…

f1c100s开发笔记

f1c100s开发笔记 全志芯片相关的论坛帖f1c100s移植帖交叉编译器的安装uboot的编译适配配置开始编译uboot编译遇坑 2020-05-20 09:56:15 星期四 全志芯片相关的论坛帖 https://whycan.cn/t_3019.html#p25005 f1c100s移植帖 https://whycan.cn/t_3211.html 交叉编译器的安装 …

全志F1C100S/F1C200S学习笔记(1)——基础简介及资料

文章目录 一、芯片概览二、芯片框图三、芯片规格四、资料:五、仓库:一、芯片概览 二、芯片框图 三、芯片规格 功能描述CPUARM9 CPU architecture16KByte D

f1c100linux系统吗,全志F1C100s怎么样 F1C100s芯片参数介绍

全志F1C100s芯片怎么样&#xff0c;F1C100s处理器好用吗&#xff1f;F1C100s是720P高清多媒体处理器。下面带来F1C100s芯片的具体参数&#xff0c;准备入手搭载F1C100s芯片设备的用户可以参考一下。 F1C100s芯片架构图 F1C100s特性介绍 支持H.264 1920x108030fps 解码 支持MJPE…

全志F1C100S的BROM研究

全志f1c100s是个性价比很高的芯片&#xff0c;但是对一般人不太友好的是它的资料开放的太少了。 网上找不到完整版的用户手册&#xff0c;只能从有限的手册文档和参考代码旁敲侧击&#xff0c;反向猜测。 关于它的BROM网上的手册内容很少。 手册上只有短短3句话&#xff1a; 具…

10、Lctech Pi(F1C200S)驱动电阻屏触摸芯片ns2009(ts2007),buildroot配置tslib(CherryPi,Mangopi,F1C100S)

本次主要参考&#xff1a; https://github.com/mangopi-sbc/buildroot-mangopi-r https://blog.csdn.net/qq_35031421/article/details/113436888 https://blog.csdn.net/dancheqishi23/article/details/116498088 &#xff08;如果方便请给这几位大佬一个关注&#xff09; 开…

F1C100S自制开发板调试过程

疫情&#xff0c;等了好久板子终于到了。 我这里使用的是坑网大佬提供的tiny200开发包&#xff0c;用的芒果派R3配置文件 1&#xff0c;配置其的介质&#xff0c;我板子上用的是nor-spi-flash,所以需要在设备树里面屏蔽掉nand-flash相关的节点&#xff0c;否则启动会有错误。 …

F1C100S(Lichee Nano)触摸屏 (GT9147)

1、前提 Ubuntu 环境版本 (18.04) Linux ubuntu 5.4.0-131-generic #147~18.04.1-Ubuntu SMP Sat Oct 15 13:10:18 UTC 2022 x86_64 x86_64 x86_64 GNU/LinuxARM GCC版本 gcc version 7.2.1 20171011 (Linaro GCC 7.2-2017.11)F1C100S Linux版本 (linux-nano-5.2-tf) 链接 …

全志F1C100s主线linux入坑记录 (5)LVGL8.2移植

LVGL8.2移植 百度网站 文章目录 LVGL8.2移植一、安装VScode二、安装lvgl模拟器二、F1c100s 移植lvgl参考 一、安装VScode 进入VScode官网下载安装包&#xff0c;如果最新版本安装有问题可以安装老版本的 https://code.visualstudio.com/使用命令行安装VScode sudo dpkg -i …

全志F1C100s主线linux入坑记录 (7)GBA模拟器移植

GBA模拟器移植 百度网站 文章目录 GBA模拟器移植一、下载gpsp 源代碼二、gpsp环境配置参考 一、下载gpsp 源代碼 gpsp源码 解压文件 7z x gpsp.7z 二、gpsp环境配置 gpsp需要SDL环境我们先在bulidroot中添加SDL包 make menuconfigTarget packages ---> Graphic libra…

9、Lctech Pi(F1C200S)开启I2C0(CherryPi,Mangopi,F1C100S)

本次主要参考&#xff1a; https://github.com/mangopi-sbc/buildroot-mangopi-r https://wiki.sipeed.com/soft/Lichee/zh/Nano-Doc-Backup/index.html &#xff08;如果方便请给这几位大佬一个关注&#xff09; 注意代码块之间的空行 配置设备树文件 1、打开linux-5.7.1/a…

全志F1C100s主线linux入坑记录 (3)适配其他分辨率的LCD

适配其他分辨率的LCD 百度网站 文章目录 适配其他分辨率的LCD一、修改U-boot屏幕参数二、修改linux内核文件三、测试效果 一、修改U-boot屏幕参数 修改对应屏幕的参数&#xff08;我这里是1024*600的屏幕&#xff09; 修改 -> ARM architecture -> Enable graphical ub…