【设计模式】单例模式代码设计

news2024/9/24 11:33:00

目录

  • 单例模式简介
  • 饿汉单例模式
  • 懒汉单例模式
  • 线程安全的懒汉单例模式

橙色
详细可参考该篇文章:C++设计模式 - 单例模式

单例模式简介

单例模式指的是,无论怎么获取,永远只能得到该类类型的唯一一个实例对象,那么设计一个单例就必须要满足下面三个条件:

1、构造函数私有化,这样用户就不能任意定义该类型的对象了
2、定义该类型唯一的对象
3、通过一个static静态成员方法返回唯一的对象实例

饿汉单例模式

饿汉式单例模式,顾名思义,就是程序启动时就实例化了该对象,并没有推迟到第一次使用该对象时再进行实例化

为什么getInstance成员函数要加static关键字?因为普通成员方法的调用还是要依赖于对象,但现在没对象,现在是通过接口来获取对象的,所以 返回唯一的对象实例的函数 应该是静态成员函数。

下面这个是饿汉式单例模式:

#include <iostream>
using namespace std;
/*
单例模式:
饿汉式单例模式:还没有获取实例对象,实例对象就已经产生了
懒汉式单例模式:唯一的实例对象,直到第一次获取它的时候,才产生
*/

//饿汉式单例模式,一定是线程安全的
class Singleton
{
public:
    static Singleton* getInstance()//#3 获取类的唯一实例对象的接口方法
    {
        return &instance;
    }
private:
    static Singleton instance;//#2 定义一个唯一类的实例对象
    Singleton()     //#1 构造函数私有化
    {

    }
    Singleton(const Singleton &) = delete;
    Singleton &operator=(const Singleton&) = delete;
};

Singleton Singleton::instance;

int main()
{
    Singleton *p1 = Singleton::getInstance();
	Singleton *p2 = Singleton::getInstance();
	Singleton *p3 = Singleton::getInstance();
    cout << p1 << " " << p2 << " " << p3 << endl;
    return 0;
}

在这里插入图片描述

但有时呢,可能你整个任务过程中都没有试图获取过该单例对象,但函数是先于程序执行载入的,那么可能饿汉模式,先定义了一个唯一的实例对象,并且构造函数进行了大量的初始化,所以在程序启动时就会先创建出一个实例化对象,白白浪费很多时间。所以有时就会用懒汉模式

懒汉单例模式

下面这个是懒汉式单例模式,把对象的实例化延迟到第一次获取该实例对象时。在程序启动时,它仅仅先创建了一个指针而不是一个对象

可重入函数:在多线程中能够被不同线程重复调用,即一个线程调用还没结束时,另一个线程又来调用,这样的函数就称为可重入函数

#include <iostream>
using namespace std;

/*
单例模式:
饿汉式单例模式:还没有获取实例对象,实例对象就已经产生了
懒汉式单例模式:唯一的实例对象,直到第一次获取它的时候,才产生
*/

//懒汉式单例模式,存在线程安全的问题
class Singleton
{
public:
    static Singleton* getInstance()//#3 获取类的唯一实例对象的接口方法
    {
        if(instance==nullptr)
        {
            instance = new Singleton();
        }
        return instance;
    }
private:
    static Singleton *instance;//#2 定义一个唯一类的实例对象
    Singleton()     //#1 构造函数私有化
    {

    }
    Singleton(const Singleton &) = delete;
    Singleton &operator=(const Singleton&) = delete;
};

Singleton* Singleton::instance=nullptr;

int main()
{
    Singleton *p1 = Singleton::getInstance();
	Singleton *p2 = Singleton::getInstance();
	Singleton *p3 = Singleton::getInstance();
    cout << p1 << " " << p2 << " " << p3 << endl;
    return 0;
}

在这里插入图片描述

线程安全的懒汉单例模式

饿汉单例模式中,单例对象定义成了一个static静态对象,它是在程序启动时,main函数运行之前就初始化好的,因此不存在线程安全问题,可以放心的在多线程环境中使用。但上面的懒汉模式代码却不是安全的

在静态成员变量instance的前面加volatile关键字,是因为在多线程中cpu为了加快速度,往往会将静态成员变量的值都拷贝一份,带到各个的线程中去,放到cpu的缓存里。而加了volatile,加了该关键字后,就禁止了各个线程拷贝该变量。如果该静态成员变量的值发生改变,那么所有的线程都会立刻看到静态成员变量的改变

下面是线程安全的懒汉单例模式:

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

/*
单例模式:
饿汉式单例模式:还没有获取实例对象,实例对象就已经产生了
懒汉式单例模式:唯一的实例对象,直到第一次获取它的时候,才产生
*/

mutex mtx;
//懒汉式单例模式=》是不是线程安全的呢?=》线程安全的懒汉式单例模式    
class Singleton
{
public:
    //是不是可重入函数呢?  锁+双重判断
    static Singleton* getInstance()//#3 获取类的唯一实例对象的接口方法
    {
        //lock_guard<mutex> guard(mtx);//在这里加锁锁的粒度太大了,如果是单线程的话,调用该函数还是要每次加锁解锁
        if(instance==nullptr)
        {
            lock_guard<mutex> guard(mtx);
            if(instance==nullptr)
            {
                /*
                开辟函数
                构造函数私有化
                给instance赋值
                */
                instance = new Singleton();
            }   
        }
        return instance;
    }
private:
    static Singleton *volatile instance;//#2 定义一个唯一类的实例对象
    Singleton()     //#1 构造函数私有化
    {

    }
    Singleton(const Singleton &) = delete;
    Singleton &operator=(const Singleton&) = delete;
};

Singleton*volatile Singleton::instance=nullptr;

int main()
{
    Singleton *p1 = Singleton::getInstance();
	Singleton *p2 = Singleton::getInstance();
	Singleton *p3 = Singleton::getInstance();
    cout << p1 << " " << p2 << " " << p3 << endl;
    return 0;
}

在这里插入图片描述

当然,线程安全的懒汉模式还有另一种写法,如下:

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

/*
单例模式:
饿汉式单例模式:还没有获取实例对象,实例对象就已经产生了
懒汉式单例模式:唯一的实例对象,直到第一次获取它的时候,才产生
*/

//懒汉式单例模式
class Singleton
{
public:
    //仅在第一次调用该函数的时候,才会创建该对象
    static Singleton* getInstance()//#3 获取类的唯一实例对象的接口方法
    {
        //函数静态局部变量的初始化,在汇编指令上已经自动添加了线程互斥指令了
        static Singleton instance;
        return &instance;
    }
private:
    Singleton()     //#1 构造函数私有化
    {

    }
    Singleton(const Singleton &) = delete;
    Singleton &operator=(const Singleton&) = delete;
};


int main()
{
    Singleton *p1 = Singleton::getInstance();
	Singleton *p2 = Singleton::getInstance();
	Singleton *p3 = Singleton::getInstance();
    cout << p1 << " " << p2 << " " << p3 << endl;
    return 0;
}

在这里插入图片描述

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

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

相关文章

麒麟inux无法打印pdf文档的Bug解决

笔者手里有一批国产linu系统&#xff0c;目前开始用在日常的工作生产环境中&#xff0c;我这个老程序猿勉为其难的充当运维的或网管的角色。 国产linu系统常见的为麒麟Linux&#xff0c;统信UOS等&#xff0c;基本都是基于debian再开发的linux。 bug描述&#xff1a; 打印机…

泛域名SSL证书

泛域名证书&#xff0c;也被称为通配符证书&#xff0c;是一种可以保护一个域名及其所有子域名的SSL/TLS证书。它使用星号&#xff08;*&#xff09;作为通配符来表示任意字符&#xff0c;因此只需一个证书就可以为多个子域提供加密服务。例如&#xff0c;如果你拥有一个名为“…

使用VBA创建Excel条件格式

实例需求&#xff1a;数据总行数不确定&#xff0c;现需要将Category区域&#xff08;即C列到J列&#xff09;中第3行开始的区域设置条件格式&#xff0c;规则如下&#xff1a; 只对部分指定单元格应用色阶条件格式&#xff08;3色&#xff09;指定单元格应满足条件&#xff1…

如何使用cpolar内网穿透工具实现公网SSH远程访问Deepin

文章目录 前言1. 开启SSH服务2. Deppin安装Cpolar3. 配置ssh公网地址4. 公网远程SSH连接5. 固定连接SSH公网地址6. SSH固定地址连接测试 前言 Deepin操作系统是一个基于Debian的Linux操作系统&#xff0c;专注于使用者对日常办公、学习、生活和娱乐的操作体验的极致&#xff0…

一文讲透Python机器学习决策树算法的基本概念与原理

1.决策树算法的基本特点与优势 决策树算法是一种有监督、非参数、简单、高效的机器学习算法。相对于非监督式学习方法&#xff0c;决策树算法由于充分利用了响应变量的信息&#xff0c;因此能够很好地克服噪声问题&#xff0c;在分类及预测方面效果更佳。决策树的决策边界为矩…

win10打开或关闭系统图标界面网络显示灰色

1、右击任务栏&#xff0c;选择任务管理器&#xff0c;或同时按下键盘上的“CtrlShiftEsc”组合键打开任务管理器&#xff1b; 2、在任务管理器【进程】选卡下找到【资源管理器】&#xff0c;单击右键&#xff0c;选择【重新启动】即可。 等待桌面和任务栏全部消失&#xff0c…

某60区块链安全之JOP实战一学习记录

区块链安全 文章目录 区块链安全Jump Oriented Programming实战一实验目的实验环境实验工具实验原理实验内容Jump Oriented Programming实战一 实验步骤分析合约源代码漏洞Jump Oriented Programming实战一 实验目的 学会使用python3的web3模块 学会分析以太坊智能合约中中Ju…

《数据库系统概论》学习笔记——王珊 萨师煊

第一章 绪论 一、数据库系统概述 1.数据库的4个基本概念 &#xff08;1&#xff09;数据 描述事物的符号记录称为数据 &#xff08;2&#xff09;数据库 存放数据的仓库 &#xff08;3&#xff09;数据库管理系统 主要功能&#xff1a; &#xff08;1&#xff09;数据定…

RabbitMQ的消息发送和接收机制

所有 MQ 产品从模型抽象上来说都是一样的过程&#xff1a; 消费者&#xff08;consumer&#xff09;订阅某个队列。生产者&#xff08;producer&#xff09;创建消息&#xff0c;然后发布到队列&#xff08;queue&#xff09;中&#xff0c;最后将消息发送到监听的消费者。 上…

【上海大学数字逻辑实验报告】四、组合电路(三)

一、 实验目的 掌握多路选择器74LS151的原理。掌握译码器74LS138的原理。学会在Quartus II上使用多路选择74LS151设计电路。学会在Quartus II上使用译码器74LS138设计电路。 二、 实验原理 多路选择器又称数据选择器或多路开关&#xff0c;它是一种多路输入单路输出的组合逻…

开启三层交换机DHCP服务

二层交换机上不需要配置任何东西&#xff0c;只需要在pc机上开启dhcp服务&#xff0c;配置好LSW1后就可以自动获取到IP地址。 sys Enter system view, return user view with CtrlZ. [Huawei]sys sw1 [sw1]dhcp enable Info: The operation may take a few seconds. Please wai…

腾讯云轻量应用服务器怎么安装BT宝塔面板?

腾讯云轻量应用服务器宝塔面板怎么用&#xff1f;轻量应用服务器如何安装宝塔面板&#xff1f;在镜像中选择宝塔Linux面板腾讯云专享版&#xff0c;在轻量服务器防火墙中开启8888端口号&#xff0c;然后远程连接到轻量服务器执行宝塔面板账号密码查询命令&#xff0c;最后登录和…

关于前端学习的思考-vertical-align的用法

先摆结论&#xff1a;vertical-align这里的top线&#xff0c;bottom线&#xff0c;middle线&#xff0c;baseline线是由最大宽度和最大高度的行内元素或行内块元素决定的。 按照惯例&#xff0c;先摆三个行内元素。 1、改变第一个盒子&#xff0c;vertical-align&#xff1a;to…

Java数据结构之《快速排序》(难度系数85)

一、前言&#xff1a; 这是怀化学院的&#xff1a;Java数据结构中的一道难度中等(偏难理解)的一道编程题(此方法为博主自己研究&#xff0c;问题基本解决&#xff0c;若有bug欢迎下方评论提出意见&#xff0c;我会第一时间改进代码&#xff0c;谢谢&#xff01;) 后面其他编程题…

网络层之无分类编址CIDR(内涵计算例题)

学习的最大理由是想摆脱平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;迟一天就多一天平庸的困扰。各位小伙伴&#xff0c;如果您&#xff1a; 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持&#xff0c;想组团高效学习… 想写博客但无从下手&#xff0c;急需…

leetcode:对称二叉树

题目描述 题目链接&#xff1a;101. 对称二叉树 - 力扣&#xff08;LeetCode&#xff09; 题目分析 题目中说至少存在一个节点&#xff0c;所以我们只需要对比左右子树 写一个子函数对比左右子树&#xff1a;用递归的思路&#xff0c;左子树的左子树和右子树的右子树对比&…

苹果电脑录屏神器,让你的录制更加轻松

“苹果电脑可以录屏吗&#xff1f;老师布置了一份作业&#xff0c;需要用到视频作为材料&#xff0c;现在我找到素材了&#xff0c;但是不知道怎么录制下来&#xff0c;非常头疼&#xff0c;大家知道苹果电脑怎么使用录屏功能吗&#xff1f;” 苹果电脑一直以其出色的性能和简…

6.17验证二叉树(LC98-M)

算法&#xff1a; 中序遍历下&#xff0c;输出的二叉搜索树节点的数值是有序序列。 有了这个特性&#xff0c;验证二叉搜索树&#xff0c;就相当于变成了判断一个序列是不是递增的了。 具体地&#xff1a;中序遍历时&#xff0c;判断当前节点是否大于中序遍历的前一个节点&a…

IntelliJ IDEA 智能(AI)编码工具插件

文章目录 通义灵码-阿里CodeGeeX-清华大学智谱AIBitoAmazon CodeWhisperer-亚马逊GitHub Copilot - 买不起CodeiumAIXcoder 仅仅自动生成单元测试功能 TestMe插件&#xff08;免费&#xff09;仅仅是模板填充&#xff0c;不智能。 Squaretest插件&#xff08;收费&#xff09;…

奇客数据恢复评论:优点、缺点和个人的结论

小型、中型和大型公司以数字格式存储大量信息。数据范围包括患者或客户信息、工资数据、联系人列表、电子邮件通信、有关个人工作和项目的各种数据以及电子表格。丢失这些数据和文件对于任何公司来说都是灾难性的。恢复这些数据对于业务的正常功能来说非常重要。 由于存在许多…