C++_单例模式

news2024/11/15 10:13:54

目录

1、饿汉方式实现单例

2、懒汉方式实现单例

3、单例模式的总结 

结语


前言:

        在C++中有许多设计模式,单例模式就是其中的一种,该模式主要针对类而设计,确保在一个进程下该类只能实例化出一个对象,因此名为单例。而单例模式又分为饿汉方式和懒汉方式,饿汉方式指的是只要发出了对该类的需求,就会实例化对象。懒汉方式指的是即使发出了对该类的需求,但是不会立刻实例化对象,等到真正用到该对象时才会实例化对象。

        示意图如下:

1、饿汉方式实现单例

         饿汉方式表明只要提出需要,则立即用该类实例化对象,并且当前进程只能有一个该类型的对象。这个逻辑在代码中的体现是:只要我们提出需要某个类的实例化请求,则系统就会立即在物理内存中就会为该对象开辟空间,即使我们不对该对象做任何的使用,该对象也会静静的放在内存中。当我们真正要访问该对象时,只能通过唯一的途径访问。

        代码实现饿汉方式:

#include <iostream>
#include <unistd.h>

using namespace std;

class Singleton
{
    Singleton()//该类不能在外被构造
    {
        cout<<"程序运行时就打印该信息"<<endl;
    }
    ~Singleton(){}//该类不能在外被析构
    Singleton(const Singleton& )=delete;//该类不能在外被拷贝
    Singleton& operator=(const Singleton& )=delete;//该类不能在外被赋值
    
    static Singleton data;//该进程下唯一Singleton对象,即单例
public:
    static Singleton *GetInstance()//外部只能通过调用该函数拿到data
    {
        return &data;
    }
};

Singleton Singleton::data;//data的初始化

int main()
{
    
    return 0;
}

        运行结果:

        从结果可以发现,代码中仅仅只是定义了一个类,还未手动对该类进行实例化,程序开始执行时系统就自动实例化了一个Singleton的data对象,因为Singleton类的构造函数被执行,说明构造了一个对象。

        对上述代码的逻辑可以理解为:定义Singleton类就是提出需求,而程序一启动就执行构造函数说明提出需求后就立即得到了一个对象


        并且在该进程下只存在唯一的Singleton类型对象,并且访问该唯一对象的途径只能是调用静态成员函数GetInstance,并且当调用GetInstance静态函数说明“真正用到了该对象”,测试代码如下:

#include <iostream>
#include <unistd.h>

using namespace std;

class Singleton
{
    Singleton()//该类不能在外被构造
    {
        cout<<"程序运行时就打印该信息"<<endl;
    }
    ~Singleton(){}//该类不能在外被析构
    Singleton(const Singleton& )=delete;//该类不能在外被拷贝
    Singleton& operator=(const Singleton& )=delete;//该类不能在外被赋值
    
    static Singleton data;//该进程下唯一Singleton对象,即单例
public:
    static Singleton *GetInstance()//外部只能通过调用该函数拿到data
    {
        return &data;
    }
};

Singleton Singleton::data;//data的初始化

int main()
{
    //以下两种实例化方式都无法实例化出对象
    // Singleton s;
    // Singleton s1(s);

    cout<<Singleton::GetInstance()<<endl;
    return 0;
}

        运行结果:

2、懒汉方式实现单例

        懒汉方式指的是当提出需求后,系统不会立即实例化出对象,而是先实例化一个指针,当真正需要用到该对象时,系统才会主动的去申请一个对象,并让该指针指向这个对象。

        懒汉方式的代码如下:

#include <iostream>
#include <unistd.h>

using namespace std;

class Singleton // 懒汉
{
    Singleton() // 该类不能在外被构造
    {
        cout << "程序运行时就打印该信息" << endl;
    }
    ~Singleton() {}                                   // 该类不能在外被析构
    Singleton(const Singleton &) = delete;            // 该类不能在外被拷贝
    Singleton &operator=(const Singleton &) = delete; // 该类不能在外被赋值

    static Singleton *data;       // 使用Singleton*作为访问唯一对象的入口
    static pthread_mutex_t lock_; // 保证线程安全
public:
    static Singleton *GetInstance() // 外部只能通过调用该函数拿到data指针
    {
        if (data == nullptr)
        {
            pthread_mutex_lock(&lock_);
            if (data == nullptr)
                data = new Singleton();
            pthread_mutex_unlock(&lock_);
        }

        return data;
    }
};

Singleton* Singleton::data = nullptr; // data的初始化
pthread_mutex_t Singleton::lock_ = PTHREAD_MUTEX_INITIALIZER;//锁的初始化

int main()
{
    
    return 0;
}

        运行结果:

        可以发现,当程序一启动时,并没有直接构造一个Singleton类型的对象,因为没有调用Singleton的构造函数,只是简单的将data指针初始化为nullptr,只有当调用静态函数GetInstance时,系统才会实例化出对象,因为调用GetInstance表示要用到该对象,这时候就可以实例化对象了。


        调用函数GetInstance的代码如下:

#include <iostream>
#include <unistd.h>

using namespace std;

class Singleton // 懒汉
{
    Singleton() // 该类不能在外被构造
    {
        cout << "程序运行时就打印该信息" << endl;
    }
    ~Singleton() {}                                   // 该类不能在外被析构
    Singleton(const Singleton &) = delete;            // 该类不能在外被拷贝
    Singleton &operator=(const Singleton &) = delete; // 该类不能在外被赋值

    static Singleton *data;       // 使用Singleton*作为访问唯一对象的入口
    static pthread_mutex_t lock_; // 保证线程安全
public:
    static Singleton *GetInstance() // 外部只能通过调用该函数拿到data指针
    {
        if (data == nullptr)
        {
            pthread_mutex_lock(&lock_);
            if (data == nullptr)
                data = new Singleton();
            pthread_mutex_unlock(&lock_);
        }

        return data;
    }
};

Singleton* Singleton::data = nullptr; // data的初始化
pthread_mutex_t Singleton::lock_ = PTHREAD_MUTEX_INITIALIZER;//锁的初始化

int main()
{
    //只有调用GetInstance时,才会开辟空间
    cout << Singleton::GetInstance() << endl;
    return 0;
}

        运行结果:

        从结果可以看到,只要真正要用到该对象,系统才会实例化该对象,没有用到该对象前,系统只有一个指针做“准备就绪”的工作。 

3、单例模式的总结 

        不管是饿汉方式还是懒汉方式,基本实现都是依靠static修饰的成员变量,并且该静态变量要放在类内,因为单例模式下构造函数是在私有域中的, 静态变量只有在类内才可以调用该类的构造函数进行初始化,这也从侧面表示出静态成员变量的类型必须和当前类的类型是一样的。拿到该类的实例化对象的途径只有通过调用该类的静态成员函数去访问。

        一般懒汉方式用的最多,因为懒汉在局部上加快了速度,因为他改变的是花费时间的结构,比如要加载某个任务,若把整个任务都加载下来则需要很多时间,但是我们可以先加载任务的一小部分先用上,而无需等待整个任务都加载下来,等到真正使用该任务的时候在进行下载,可以将空间利用率最大化。

结语

        以上就是关于单例模式的讲解,单例模式下用的最多的是懒汉方式,因为他可以将内存的空间利用率最大化,无论是饿汉方式还是懒汉方式,本质上是利用了static静态变量在进程的唯一性。

        最后如果本文有遗漏或者有误的地方欢迎大家在评论区补充,谢谢大家!! 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1941161.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OpenCV 图像旋转和平移 数学和代码原理详解

文章目录 数学原理旋转矩阵平移和旋转合成变换矩阵应用在OpenCV中的实现 代码关键点解读完整代码C代码&#xff1a;Python代码&#xff1a; 在OpenCV中进行图像旋转涉及到一些基本的几何变换和图像处理操作。 数学原理 在图像旋转中&#xff0c;背后的数学原理主要涉及二维欧…

嵌入式硬件-Xilinx FPGA DDR4 接口配置基础(PG150)

1. 简介 1.1 DDR4 SDRAM 控制器主要特点 支持8到80位接口宽度的组件&#xff08;支持 RDIMM、LRDIMM、UDIMM 和 SODIMM&#xff09; 最大组件限制为9&#xff0c;此限制仅适用于组件&#xff0c;不适用于 DIMM。密度支持 最高支持 32 GB 的组件密度&#xff0c;64 GB 的 LRDI…

步步精慕尼黑上海电子展完美收官,感恩所有相遇,期待下次再会

2024年7月11日至13日&#xff0c;慕尼黑上海电子展圆满落幕&#xff0c;步步精科技&#xff08;以下简称步步精&#xff09;在此次展会上取得了丰硕的成果。作为连接器行业的重要制造商&#xff0c;步步精携带其最新产品和连接器技术方案亮相展会&#xff0c;吸引了大量参观者的…

【HarmonyOS】HarmonyOS NEXT学习日记:六、渲染控制、样式结构重用

【HarmonyOS】HarmonyOS NEXT学习日记&#xff1a;六、渲染控制、样式&结构重用 渲染控制包含了条件渲染和循环渲染&#xff0c;所谓条件渲染&#xff0c;即更具状态不同&#xff0c;选择性的渲染不同的组件。 而循环渲染则是用于列表之内的、多个重复元素组成的结构中。 …

RK3568笔记四十二:OLED 屏幕驱动(模拟I2C)

若该文为原创文章&#xff0c;转载请注明原文出处。 本篇记录使用GPIO模拟I2C驱动OLED屏幕&#xff0c;显示界面效果如下。 主要流程是&#xff0c;修改设备树&#xff0c;使用普通IO口&#xff0c;驱动模拟I2C方式&#xff0c;应用程直接传输数据控制。 1、修改设备 2、编写…

Go语言 Import导入

本文主要介绍Go语言import导入使用时注意事项和功能实现示例。 目录 Import 创建功能文件夹 加法 减法 主函数 优化导入的包名 .引入方法 总结 Import 创建功能文件夹 做一个计算器来演示&#xff0c;首先创建test文件夹。 加法 在test文件夹中创建add文件夹&#xff…

数据预处理在建模中的重要性与常见方法(三):特征工程篇

数据预处理在建模中的重要性与常见方法&#xff08;三&#xff09;&#xff1a;特征工程篇 特征工程是数据预处理中至关重要的一步&#xff0c;通过构建、转换和选择最能代表数据特性的特征&#xff0c;以提高模型的性能和准确性。常见的特征工程方法包括特征选择、特征提取和特…

前端-模拟请求数据mook第三方插件 json-server的使用

大纲 第一步下载第二配置mook的数据源第三配置启动命令第四运行模拟服务第五测试接口如果要进行更复杂的操作 第一步下载 npm install json-server -D"devDependencies": {"json-server": "^1.0.0-beta.1"}第二配置mook的数据源 在项目的根目录…

某指挥调度系统功能展示(下)

照片管理 拍照是普通执勤巡检中很常用的信息记录功能。 通过此功能可以看到设备本地拍摄的照片&#xff0c;此平台分成了两部分&#xff1a; 一部分是设备上的&#xff0c;需要设备在线才可以访问&#xff1b;支持上传到平台&#xff0c;并且在设备端有相应的选择&#xff0…

人、智能、机器人……

在遥远的未来之城&#xff0c;智能时代如同晨曦般照亮了每一个角落&#xff0c;万物互联&#xff0c;机器智能与人类智慧交织成一幅前所未有的图景。这座城市&#xff0c;既是科技的盛宴&#xff0c;也是人性与情感深刻反思的舞台。 寓言&#xff1a;《智光与心影》 在智能之…

Linux性能分析之-CPU篇

开发车载软件app&#xff0c;除了常用Android操作系统外&#xff0c;还可能是基于Linux系统开发。对于web应用基本也都部署在Linux系统上&#xff0c;所以&#xff0c;进行系统性能分析&#xff0c;很大情况下都是对Linux系统进行性能分析。此篇博客将重点介绍如果收集CPU相关指…

GPT-4o mini是什么?

今天&#xff0c;全网都知道 OpenAI 发现货了&#xff01; GPT-4o mini 取代 GPT 3.5&#xff0c;从此坐上正主之位。 从官网信息来看&#xff0c;OpenAI 最新推出的 GPT-4o mini 重新定义了 AI 成本效益的标准&#xff0c;其性能优于前代模型 GPT-3.5 Turbo&#xff0c;且成本…

SpringBoot系列—4.SpringBoot 整合Mybatis、MP(MyBatis-Plus)

SpringBoot系列—1.IDEA搭建SpringBoot框架 SpringBoot系列—2.SpringBoot拦截器篇 SpringBoot系列—3.SpringBoot Redis篇 SpringBoot系列—4.SpringBoot 整合Mybatis、MP&#xff08;MyBatis-Plus&#xff09; SpringBoot系列—5.SpringBoot 整合Mybatis-Plus分页 **1.pom.xm…

设计模式-Git-其他

目录 设计模式&#xff1f; 创建型模式 单例模式&#xff1f; 啥情况需要单例模式 实现单例模式的关键点&#xff1f; 常见的单例模式实现&#xff1f; 01、饿汉式如何实现单例&#xff1f; 02、懒汉式如何实现单例&#xff1f; 03、双重检查锁定如何实现单例&#xff…

【扩散模型(五)】IP-Adapter 源码详解3-推理代码

系列文章目录 【扩散模型&#xff08;一&#xff09;】中介绍了 Stable Diffusion 可以被理解为重建分支&#xff08;reconstruction branch&#xff09;和条件分支&#xff08;condition branch&#xff09;【扩散模型&#xff08;二&#xff09;】IP-Adapter 从条件分支的视…

前端JS特效第48集:terseBanner焦点图轮播插件

terseBanner焦点图轮播插件&#xff0c;先来看看效果&#xff1a; 部分核心的代码如下(全部代码在文章末尾)&#xff1a; <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatibl…

python每日学习:异常处理

python每日学习8&#xff1a;异常处理 Python中的错误可以分为两种&#xff1a;语法错误和异常 语法错误(Syntax errors) &#xff1a;代码编译时的错误&#xff0c;不符合Python语言规则的代码会停止编译并返回 错误信息。 缺少起始符号或结尾符号(括号、引号等)。 缩进错误…

算法篇 滑动窗口 leetCode 30 串联所有单词的子串

串联所有单词的子串 1.题目描述2.题目解释2.1 原理解释2.2 文字分析 3.代码演示 1.题目描述 2.题目解释 2.1 原理解释 2.2 文字分析 3.代码演示

移动硬盘在苹果电脑上使用后在windows中无法读取 Win和Mac的硬盘怎么通用

在日益普及的跨平台工作环境中&#xff0c;苹果电脑与Windows PC之间的数据交换成为日常需求。然而&#xff0c;用户常面临一个困扰&#xff1a;为何苹果电脑的硬盘能在macOS下流畅运行&#xff0c;却在Windows系统中变得“水土不服”&#xff1f;这一问题核心在于硬盘格式的不…

mac docker no space left on device

mac 上 docker 拉取镜像报错 Error response from daemon: write /var/lib/docker/tmp/docker-export-3995807640/b8464f52498789c4ebbc063d508f04e8d2586567fbffa475e3cd9afd3c5a7cf2/layer.tar: no space left on device解决&#xff1a; 增加 docker 虚拟磁盘大小。如下图