C++常用23种设计模式总结(一)------单例模式

news2024/12/29 8:02:58

什么是单例模式

单例模式是一种设计模式,它保证一个类只有一个实例,并提供一个全局访问点来访问该实例。这个模式通常用于控制资源的访问,例如数据库连接、线程池等。单例模式通过限制实例化操作并提供访问方法,确保在整个应用程序中只存在一个实例,避免了多个实例之间的冲突和资源浪费。

在单例模式中,类的构造函数被私有化,使得外部无法直接实例化该类。同时,在类的内部创建一个私有静态变量来保存唯一的实例,然后提供一个静态方法来访问该实例。这个静态方法会检查实例是否已经存在,如果存在则返回原有实例,否则创建一个新的实例并返回。这样就可以保证在任何时候,整个应用程序中只有一个实例存在。

需要注意的是,单例模式不是线程安全的。在多线程环境下,可能会出现多个线程同时访问单例对象的情况。为了解决这个问题,可以使用双重检查锁定等技术来确保线程安全。

单例模式一般有两种创建方法:

1、饿汉式
2、懒汉式

这两种的含义后续在作说明。

代码实现–懒汉式

  • jk.cpp
#include <iostream>

class jk
{
private:
    jk(){ std::cout << "i am jk" << std::endl; }
    ~jk() { std::cout << "i am ~ jk" << std::endl; }
    jk(jk&) = delete;
	jk& operator=(const jk&) = delete;
public:
    static jk *GetjkPoint()
    {
        if (ptr == nullptr)
        {
            std::cout << "jk init ptr is nullptr" << std::endl;
            ptr = new jk();
        }
        return ptr;
    }

public:
    void out() { std::cout << "hello world!" << std::endl; }

private:
    static jk *ptr;
};

jk * jk::ptr = nullptr;

int main()
{
    jk::GetjkPoint()->out();
    return 0;
}

编译运行

g++ jk.cpp -std=c++11 -o jk
./jk

运行结果

jk init ptr is nullptr
i am jk
hello world

细心的就会发现上诉代码有如下问题

线程安全的问题,当多线程获取单例时有可能引发竞态条件:第一个线程在if中判断 ptr是空的,于是开始实例化单例;同时第2个线程也尝试获取单例,这个时候判断ptr还是空的,于是也开始实例化单例;这样就会实例化出两个对象,这就是线程安全问题的由来; 解决办法:加锁

内存泄漏. 注意到类中只负责new出对象,却没有负责delete对象因此只有构造函数被调用,析构函数却没有被调用;因此会导致内存泄漏。解决办法1:当然我们自己手动调用delete来进行释放是可以的,但是维护在何处释放又成了问题。

我们可以做如下优化:

#include <iostream>

class jk
{
private:
    jk(){ std::cout << "i am jk" << std::endl; }
    ~jk() { std::cout << "i am ~ jk" << std::endl; }
    jk(jk&) = delete;
	jk& operator=(const jk&) = delete;
public:
    static jk *GetjkPoint()
    {
        if (ptr == nullptr)
        {
            std::cout << "jk init ptr is nullptr" << std::endl;
            ptr = new jk();
            static garbo garboobj;
        }
        return ptr;
    }

public:
    void out() { std::cout << "hello world!" << std::endl; }

private:
    class garbo
    {
        public:
            ~garbo()
            {
                if(ptr != nullptr)
                {
                    delete ptr;
                    ptr = nullptr;
                }
            }
    };

private:
    static jk *ptr;
};

jk * jk::ptr = nullptr;
int main()
{
    jk::GetjkPoint()->out();
    return 0;
}

输出结果:

jk init ptr is nullptr
i am jk
hello world!
i am ~ jk

我们还可以使用智能指针实现如下优化

#include <iostream>
#include <memory> // C++11 shared_ptr头文件
#include <mutex>  // C++11 mutex头文件
class jk
{
private:
    jk() { std::cout << "i am jk" << std::endl; }
    // ~jk() { std::cout << "i am ~ jk" << std::endl; }
    jk(jk &) = delete;
    jk &operator=(const jk &) = delete;

public:
    ~jk() { std::cout << "i am ~ jk" << std::endl; }

public:
    static std::shared_ptr<jk> GetjkPoint()
    {
        if (ptr == nullptr)
        {
            std::lock_guard<std::mutex> lk(m_tex);
            std::cout << "jk init ptr is nullptr" << std::endl;
            if(ptr == nullptr)
            {
                // ptr = std::make_shared<jk>();
                ptr = std::shared_ptr<jk>(new jk());
            }
        }
        return ptr;
    }

public:
    void out() { std::cout << "hello world!" << std::endl; }

private:
    static std::shared_ptr<jk> ptr;
    static std::mutex m_tex;
};

std::shared_ptr<jk> jk::ptr = nullptr;
std::mutex jk::m_tex;
int main()
{
    jk::GetjkPoint()->out();
    return 0;
}

运行可以发现:

jk init ptr is nullptr
i am jk
hello world!
i am ~ jk

析构已经可以跑到了。

代码实现–饿汉式

#include <iostream>

class jk
{
private:
    jk(){ std::cout << "i am jk" << std::endl; }
    ~jk() { std::cout << "i am ~ jk" << std::endl; }
    jk(jk&) = delete;
	jk& operator=(const jk&) = delete;
public:
    static jk *GetjkPoint()
    {

        return ptr;
    }

public:
    void out() { std::cout << "hello world!" << std::endl; }

private:
    class garbo
    {
        public:
            ~garbo()
            {
                if(ptr != nullptr)
                {
                    delete ptr;
                    ptr = nullptr;
                }
            }
    };

private:
    static jk *ptr;
    static garbo garboobj;
};

jk * jk::ptr = new jk();
jk::garbo jk::garboobj;
int main()
{
    jk::GetjkPoint()->out();
    return 0;
}

运行结果:

i am jk
hello world!
i am ~ jk

看完上述代码会发现:

饿汉式 :程序一执行,不管是否被调用,先new出来。这种创建方法不受多线程的困扰。缺点也很明显
必须在jk * jk::ptr = new jk();之后才能使用静态类中的方法(jk::GetjkPoint()->out();)。否则ptr的值是nullptr,程序直接挂了。

懒汉式:使用时才会被new出来,但是要考虑多线程问题。

最后

以上这些方法还是比较繁琐的,最安全最简洁的方法如下。

#include <iostream>
class jk
{
private:
    jk() { std::cout << "i am jk" << std::endl; }
    // ~jk() { std::cout << "i am ~ jk" << std::endl; }
    jk(jk &) = delete;
    jk &operator=(const jk &) = delete;

public:
    ~jk() { std::cout << "i am ~ jk" << std::endl; }

public:
    static jk& GetjkPoint()
    {
        static jk ptr;
        return ptr;
    }

public:
    void out() { std::cout << "hello world!" << std::endl; }
};

int main()
{
    jk::GetjkPoint().out();
    jk::GetjkPoint().out();
    return 0;
}

运行结果:

i am jk
hello world!
hello world!
i am ~ jk

总结不易,如果可以 ^ _ ^
别忘了带赞收藏哦!
您的肯定,是我持续更下去的动力。哒咩~~
在这里插入图片描述

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

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

相关文章

【Unity3D小功能】Unity3D中实现模型的旋转、缩放效果(控制摄像机)

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址我的个人博客 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 其实之前已经写了关于如何控制模型的旋转、移动、缩放效果&…

Android开发:使用sqlite数据库实现记单词APP

一、功能与要求 实现功能&#xff1a;设计与开发记单词系统的四个界面&#xff0c;分别是用户登录、用户注册、单词操作以及忘记密码。 指标要求&#xff1a;通过用户登录、用户注册、单词操作、忘记密码掌握界面设计的基础&#xff0c;其中包括界面布局、常用控件、事件处理等…

NPN三极管放大原理

NPN三极管放大 这是华为的芯片,还有其他人的芯片 无论这些芯片再复杂,它们都是由这种材料制成的 ​ 硅晶体 我们把他放大,单个硅原子最外层带有四个电子, 在纯硅当中,这些电子会两两形成共价键,此时周围形成非常稳定的八电子结构 我们接上电池, 电池无法吸引其中的电子离开,也…

不止大模型,亚马逊云科技布局AIGC底座能力

“大模型只是客户需求的其中一个部分&#xff0c;但远远不是所有&#xff0c;客户还需要更广泛的基础能力。亚马逊云科技推出自研芯片、生成式AI服务Bedrock以及大模型Titan&#xff0c;都在致力于推动AIGC技术的普惠化&#xff0c;够降AIGC的技术门槛和资金门槛&#xff0c;让…

万应低代码4月重点更新内容速递

低代码开发能力提升 分布式缓存支持 万应提供了一套分布式的缓存系统&#xff0c;可在多个节点之间共享缓存数据&#xff0c;从而加速数据获取速度&#xff0c;提高应用的性能和效率。包含&#xff1a; 缓存设置节点&#xff1a;把需要高频访问的数据写入到缓存中&#xff0c;并…

vue3 vue.config.js配置Element-plus组件和Icon图标实现按需自动引入

打包时&#xff0c;报警告&#xff0c;提示包太大会影响性能 1.配置前包体积&#xff1a; 2.安装插件&#xff1a; npm i unplugin-auto-import unplugin-vue-components unplugin-icons -D 3.vue.config.js中加入以下配置&#xff1a; const { defineConfig } require(vu…

Vue3 Antd 父子嵌套子表格

Vue3 Antd 父子嵌套子表格 父子嵌套子表格 目标1&#xff1a;可以点击多个父节点表格&#xff0c;正确显示子表格数据 目标2&#xff1a;父表格数据刷新重载&#xff0c;解决子表格数据不刷新问题 官方示例代码&#xff0c;以及效果 https://www.antdv.com/components/tabl…

linux0.12-8-2-asm.s

[290页] 8-2 asm.s程序 8-2-1 功能描述 1、 我们先考虑c)、 d) 2、无出错码 2.1、 将要执行的处理函数压栈&#xff1b; 2.2、 eax被交换入栈。现在eax护理函数 2.3、 其他寄存压栈 2.4、 立即数0压栈 2.5、 取edxEIP后&#xff0c;将edx压栈 2.6、 段寄存器都设置0x10段选…

通过身份个性化网络(IPM)实现真实世界的自动化妆

来源&#xff1a;投稿 作者&#xff1a;小灰灰 编辑&#xff1a;学姐 论文标题&#xff1a; Real-World Automatic Makeup via Identity Preservation Makeup Net 论文链接&#xff1a;https://www.ijcai.org/proceedings/2020/0091.pdf论文代码&#xff1a;https://github.co…

XRSPACE 总经理刘冠廷:元宇宙行业如何通过 2D、3D 联动,实现高速用户增长?

序言&#xff1a; 元宇宙领域创业并非坦途&#xff0c;似乎已经成为了行业共识。 即使到今天&#xff0c;VR/AR 领域的装备开支和上手学习成本居高不下&#xff0c;全球整体用户体量相比移动互联网也仍属早期阶段。 在这样的背景下&#xff0c;元宇宙公司如何持续且快速地获…

python毕业设计之django+vue流浪宠物动物救助领养网站

开发语言&#xff1a;Python 框架&#xff1a;django Python版本&#xff1a;python3.7.7 数据库&#xff1a;mysql 数据库工具&#xff1a;Navicat 开发软件&#xff1a;PyCharm 网站前台&#xff1a; 站内新闻&#xff1a;针对网站的新闻信息进行展示&#xff0c;能够展示…

简单聊聊Echarts伪3D地图实现的相关配置

知识和技能真的是用进废退&#xff0c;还是得多实践&#xff0c;才不至于遗忘。 目录 前言 二、实现原理 三、从0开始实现 1.目录结构 2.地图JSON数据获取 3.具体实现&#xff0c;重头戏 3.一些常见问题的解决方法 总结 前言 本文简单来聊一聊Echarts伪3D地图的实现&a…

Java面试被问Spring哑口无言?100道Spring面试考点解析

对于开发同学来说&#xff0c;Spring 框架熟悉又陌生。 熟悉&#xff1a;开发过程中无时无刻不在使用 Spring 的知识点&#xff1b;陌生&#xff1a;对于基本理论知识疏于整理与记忆。导致很多同学面试时对于 Spring 相关的题目知其答案&#xff0c;但表达不够完整准确。今天展…

UE4蓝图学习篇(八)-- 角色基础移动

在C学习篇中有介绍如何使用UE4C去处理角色的基础移动&#xff0c;那么本篇介绍使用蓝图去处理角色的基础移动。 1、创建Character类&#xff1b; 添加一个SpringArmComponent组件&#xff0c;在其下方添加一个CameraComponent组件能够看到角色&#xff0c;SpringArmComponent的…

奥斯汀独家对话|从机构的「拉扯」中成长的美国加密监管

‍前言 4月25日&#xff0c;在美国得克萨斯州的首府奥斯汀&#xff0c;这座充满活力和创造力的城市&#xff0c;欧科云链研究院与来自哥伦比亚商学院的Austin Campbell教授就美国加密监管以及其相关话题进行了一次深入探讨。双方讨论了美国整体的监管问题、监管逻辑、最新的稳…

华为孟晚舟当值首秀:2030年AI算力将增长500倍!

作者 | 范智林 来源 | 华商观察 微信号&#xff1a;HuashangGC 孟晚舟当值首次亮相。 4月19日&#xff0c;华为副董事长、轮值董事长、CFO孟晚舟在华为第20届全球分析师大会上进行演讲&#xff0c;这是她当值华为轮值董事长以来的首次公开亮相。 按照华为内部规定&#xff0c…

展会预告 | 昂视诚邀您届时莅临CIBF2023深圳国际电池展

CIBF2023深圳国际电池展将于5月16日在深圳国际会展中心&#xff08;宝安新馆&#xff09;举行&#xff0c;作为国际电池行业规模最大的会展活动&#xff0c;它是了解电池行业的重要窗口&#xff0c;也是中国电池产业链企业连接全球产业界的重要桥梁和平台。 昂视作为制造自动化…

一文彻底分清ARM架构、内核、指令集等相关概念

任何学习嵌入式/单片机的朋友都绕不开ARM&#xff0c;但初学者总是对ARM架构、内核、指令集等相关概念不够清晰或者混淆&#xff0c;本文帮助入门的朋友彻底弄清楚。 目录 1.芯片、CPU、SOC 2.ARM公司 3.ARM架构与内核、指令集 3.1架构与内核 3.2架构与指令集 4.ARM架构…

操作系统——概述

目录 1.1初识操作系统 思考题&#xff1a; 1.2操作系统的功能和定义 思考题&#xff1a; 1.3操作系统发展史 思考题&#xff1a; 1.4分时技术 思考题&#xff1a; 1.5典型操作系统类型 1.1初识操作系统 常见桌面级别的四大操作系统&#xff1a;Windows、Mac OS、Linu…

swift 技术 音频

一直觉得自己写的不是技术&#xff0c;而是情怀&#xff0c;一个个的教程是自己这一路走来的痕迹。靠专业技能的成功是最具可复制性的&#xff0c;希望我的这条路能让你们少走弯路&#xff0c;希望我能帮你们抹去知识的蒙尘&#xff0c;希望我能帮你们理清知识的脉络&#xff0…