23种经典设计模式:单例模式篇(C++)

前言:        

        博主将从此篇单例模式开始逐一分享23种经典设计模式,并结合C++为大家展示实际应用。内容将持续更新,希望大家持续关注与支持。

什么是单例模式?

        单例模式是设计模式的一种(属于创建型模式 (Creational Patterns) ),它确保某个类只有一个实例,并为该实例提供一个全局访问点。它常用于那些在整个系统中只需要一个实例的类,例如配置管理、日志记录、线程池、缓存等。

为什么选择单例模式?

1. 确保唯一性

        有些时候,我们需要确保某个对象在整个系统中只存在一个。这样可以避免因为多次实例化导致的资源浪费或不一致性。

2. 节省资源

        如果一个对象初始化需要大量资源,例如读取配置文件或建立数据库连接,那么多次实例化就可能导致不必要的开销。

3. 提供全局访问点

        这让其他对象可以轻松地访问到该实例,并与之交互。

4. 单例模式的不足:

        万事万物都没有绝对的好,不然也不会有23种设计模式,过度依赖单例模式可能使代码变得紧耦合和难以测试。因此,当考虑使用单例模式时,应当仔细权衡其优点和潜在的问题。        

单例模式的分类?

单例模式的具体实现? 

1. 饿汉式

  • 特点:在类加载时就完成了初始化,静态成员对象的创建是在类加载时完成的。
  • 优点:线程安全(基于类加载机制,避免了多线程同步问题)。
  • 缺点:不是懒加载,可能造成资源浪费。
class Singleton {
private:
    // Singleton的私有静态实例
    static Singleton instance;

    // 私有构造函数确保只能通过getInstance方法来访问Singleton实例
    Singleton() {}

public:
    // 公共静态方法,用于获取Singleton实例
    static Singleton& getInstance() {
        return instance;
    }
};

// 初始化静态的Singleton实例
Singleton Singleton::instance;

2. 懒汉式

  • 特点:在第一次调用时实例化。
  • 优点:懒加载,只有在真正需要对象时才会创建。
  • 缺点:需要处理线程安全问题。
class Singleton {
private:
    // Singleton的私有静态指针实例
    static Singleton* instance;

    // 私有构造函数确保只能通过getInstance方法来访问Singleton实例
    Singleton() {}

public:
    // 公共静态方法,用于获取Singleton实例。如果实例不存在,就创建一个。
    static Singleton* getInstance() {
        if (!instance) { // 判断instance是否为空
            instance = new Singleton(); // 如果为空,则新建一个Singleton对象
        }
        return instance; // 返回Singleton对象的指针
    }
};

// 初始化静态的Singleton指针实例为nullptr
Singleton* Singleton::instance = nullptr;

 3. 懒汉式(带锁)

  • 特点:在首次请求对象时创建实例,但加入了互斥锁以确保线程安全。
  • 优势:懒加载,线程安全。
  • 劣势:每次访问时都需要加锁,可能会有性能开销。
class Singleton {
private:
    static Singleton* instance;
    static std::mutex mtx; // 用于同步的互斥锁

    Singleton() {}

public:
    static Singleton* getInstance() {
        std::lock_guard<std::mutex> lock(mtx); // 直接锁定
        if (!instance) {
            instance = new Singleton();
        }
        return instance;
    }
};

Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;

4. 双重检查锁定(DCL, Double Checked Locking)

  • 特点:结合了懒汉式和synchronized同步锁。
  • 优点:懒加载,线程安全,且性能较高。
class Singleton {
private:
    // Singleton的私有静态指针实例
    static Singleton* instance;
    
    // 用于同步的互斥锁
    static std::mutex mtx;

    Singleton() {}

public:
    // 这里使用了双重检查锁定来确保线程安全
    static Singleton* getInstance() {
        if (!instance) { // 第一次检查,不加锁
            std::lock_guard<std::mutex> lock(mtx); // 加锁
            if (!instance) { // 第二次检查,已加锁
                instance = new Singleton(); 
            }
        }
        return instance; 
    }
};

Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;

5. 静态局部变量(C++11)

        利用C++11特性,局部静态变量已经是线程安全的,并且无需额外的锁或同步机制。

class Singleton {
public:
    // 公共静态方法,用于获取Singleton实例的引用。
    // 这里利用了局部静态变量的特性,该变量只会初始化一次,并且这个初始化过程在C++11及以上是线程安全的。
    static Singleton& getInstance() {
        static Singleton instance;  // 局部静态变量
        return instance;            // 返回这个局部静态变量的引用
    }

private:
    // 私有构造函数确保只能通过getInstance方法来访问Singleton实例
    Singleton() {}
};

6. 使用std::once_flagstd::call_once(C++11及以上):

  • 特点:确保某个代码块只被执行一次。
  • 优势:线程安全,性能较好。
  • 劣势:依赖于C++11及以上版本的特性。
class Singleton {
private:
    // Singleton的私有静态指针实例
    static Singleton* instance;
    static std::once_flag onceFlag;

    // 私有构造函数
    Singleton() {}

public:
    // 删除拷贝构造函数和赋值操作符,确保不能拷贝
    Singleton(const Singleton& other) = delete;
    Singleton& operator=(const Singleton& other) = delete;

    // 公共静态方法,用于获取或创建Singleton实例
    static Singleton* getInstance() {
        std::call_once(onceFlag, []() {
            instance = new Singleton();
        });
        return instance;
    }
};

// 初始化静态成员
Singleton* Singleton::instance = nullptr;
std::once_flag Singleton::onceFlag;

开发中的选择?

在实际开发中,选择单例模式的具体实现通常取决于以下因素:

  1. 线程安全性需求:在多线程应用中,单例模式的实现必须是线程安全的。但如果你知道应用永远不会在多线程环境中运行,你可以选择一个不考虑线程安全的简单实现。

  2. 性能考虑:某些单例实现(例如每次访问时都加锁的懒汉式)可能会对性能产生负面影响。但在现代硬件上,这种影响通常可以忽略不计,除非你的代码在高频、高并发场景下运行。

  3. C++版本:在C++11及更高版本中,局部静态变量的初始化是线程安全的,这使得某些单例实现变得更为简洁和可靠。

基于上述因素,以下是在实际开发中经常使用的单例模式实现:

  1. 局部静态变量(推荐,尤其是C++11及以上):

    这种方法简洁、线程安全,并且无需额外的锁或同步机制。

  2. 双重检查锁定(DCL, Double Checked Locking): 这在C++11之前可能是线程安全的选择,但需要谨慎使用,因为在某些老的编译器和硬件上可能会出现问题。

  3. 使用std::call_oncestd::once_flag: 这是C++11及以上版本提供的线程安全方法,可以确保对象只初始化一次。

  4. 饿汉式: 在程序启动时就创建实例。这种方法简单并且线程安全,但可能会导致不必要的资源浪费,特别是当单例对象很大或初始化成本很高时。

  5. 懒汉式(带锁): 在首次请求时创建实例,并使用互斥锁确保线程安全。这种方式在性能敏感的场景中可能不是最佳选择。

结论:

        单例模式有许多不同的实现,每种实现都有其适用的场景和优缺点。在实践中,选择哪种实现需要根据具体需求和上下文进行权衡。

        本文侧重于介绍单例模式在C++中的使用方法,若读者有不同的的理解和看法,欢迎在评论区留言!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

多功能智慧路灯系统整体解决方案介绍

在不改变现有城市景观的前提下&#xff0c;利用现有路灯改造&#xff0c;或新建多功能叁仟智慧路灯的方法&#xff0c;可实现城市无线网络、视频监控、物联传感网络、新能源充电系统、网格信息化管理的全覆盖&#xff0c;有效解决信息化设备选址难、取电难等问题。在目前无线通…

87基于matlab的双卡尔曼滤波算法

基于matlab的双卡尔曼滤波算法。第一步使用了卡尔曼滤波算法&#xff0c;用电池电压来修正SOC&#xff0c;然后将修正后的SOC作为第二个卡尔曼滤波算法的输入&#xff0c;对安时积分法得到的SOC进行修正&#xff0c;最终得到双卡尔曼滤波算法SOC估计值。结合EKF算法和安时积分法…

pytorch实现遥感建筑物提取

如何自动地从高分辨率遥感影像中提取建筑物等人工目标是高分辨率遥感影像处理与理解领域的一个热点与难点问题。本篇文章我们将学习如何使用pytorch实现遥感建筑物的智能提取。 智能提取的流程 基于深度学习的遥感建筑物智能提取&#xff0c;首先需要制作数据集&#xff0c;然后…

【Java数据结构 -- 包装类和泛型】

包装类和泛型 1. 包装类1.1 基本数据类型和对应的包装类1.2 装箱和拆箱1.3 自动装箱和自动拆箱1.4 自动装箱实际上是调用了valueOf&#xff08;&#xff09;1.5 Integer包装类赋值注意点 2 什么是泛型3 引出泛型4 泛型的使用4.1 语法4.2 类型推导 5 裸类型6 泛型如何编译6.1 擦…

C++-继承

一. 继承的概念及定义 1 . 继承的概念 继承(inheritance) 机制是面向对象程序设计 使代码可以复用 的最重要的手段&#xff0c;它允许程序员在 保 持原有类特性的基础上进行扩展 &#xff0c;增加功能&#xff0c;这样产生新的类&#xff0c;称派生类。继承 呈现了面向对象 程…

亚马逊、eBay店铺如何提升销量转化?掌握测评自养号的技巧

跨境电商随着互联网和物流技术的迅速发展&#xff0c;消费者可以更轻松地借助跨境电商平台在全球范围内进行购物&#xff0c;而提到跨境电商&#xff0c;亚马逊平台是不可忽视。 在竞争激烈的亚马逊市场中&#xff0c;提升销量转化率是每个卖家都追求的目标&#xff0c;高转化…

企业被列入经营异常会有什么后果?

1、工商方面的不良影响 被工商纳入异常吊销营业执照&#xff1a;公司地址异常将会被工商部门纳入经营异常名录&#xff0c;需要及时申请移出&#xff0c;否则会影响正常经营&#xff0c;严重则有被吊销营业执照的风险。 影响企业形象及信誉度&#xff1a;企业间的合作都非常重视…

git报错:error: RPC failed; HTTP 413 curl 22 The requested URL returned error: 413

git报错&#xff1a;error: RPC failed; HTTP 413 curl 22 The requested URL returned error: 413 如图&#xff1a; error: RPC failed; HTTP 413 curl 22 The requested URL returned error: 413 send-pack: unexpected disconnect while reading sideband packet fatal: th…

【C语言】【选择排序及其优化】

选择排序是指&#xff1a;第一次从待排序的数据元素中选出最小&#xff08;或最大&#xff09;的一个元素&#xff0c;存放在序列的起始位置&#xff0c;然后再从剩余的未排序元素中寻找到最小&#xff08;大&#xff09;元素&#xff0c;然后放到已排序的序列的末尾&#xff0…

代码随想录算法训练营第六十天|84. 柱状图中最大的矩形

LeetCode 84. 柱状图中最大的矩形 题目链接&#xff1a;84. 柱状图中最大的矩形 - 力扣&#xff08;LeetCode&#xff09; 和接雨水还挺像的。 代码&#xff1a; #python class Solution:def largestRectangleArea(self, heights: List[int]) -> int:heights.insert(0, 0…

Intel Software Guard Extensions简介

文章目录 前言一、新的基于硬件的控件实现数据安全二、机密计算的挑战三、用于机密计算的增强安全功能四、Enclave验证和数据密封五、数据中心认证参考资料 前言 最近开始研究Intel SGX硬件特性&#xff0c;记录下研究过程。 参考文档&#xff1a;product-brief-SGX 一、新的…

python实现自动刷平台学时

背景 前一阵子有个朋友让我帮给小忙&#xff0c;因为他每学期都要看视频刷学时&#xff0c;一门平均需要刷500分钟&#xff0c;一学期有3-4门需要刷的。 如果是手动刷的话&#xff0c;比较麻烦&#xff0c;能否帮他做成自动化的。搞成功的话请我吃饭。为了这顿饭&#xff0c;咱…

Redis的五大数据类型详细用法

我们说 Redis 相对于 Memcache 等其他的缓存产品&#xff0c;有一个比较明显的优势就是 Redis 不仅仅支持简单的key-value类型的数据&#xff0c;同时还提供list&#xff0c;set&#xff0c;zset&#xff0c;hash等数据结构的存储。本篇博客我们就将介绍这些数据类型的详细使用…

Javaweb之Vue组件库Element之Dialog对话框的详细解析

4.3.3 Dialog对话框 4.3.3.1 组件演示 Dialog: 在保留当前页面状态的情况下&#xff0c;告知用户并承载相关操作。其企业开发应用场景示例如下图所示 首先我们需要在ElementUI官方找到Dialog组件&#xff0c;如下图所示&#xff1a; 然后复制如下代码到我们的组件文件的templ…

「江鸟中原」有关HarmonyOS-ArkTS的Http通信请求

一、Http简介 HTTP&#xff08;Hypertext Transfer Protocol&#xff09;是一种用于在Web应用程序之间进行通信的协议&#xff0c;通过运输层的TCP协议建立连接、传输数据。Http通信数据以报文的形式进行传输。Http的一次事务包括一个请求和一个响应。 Http通信是基于客户端-服…

Go 数字类型

一、数字类型 1、Golang 数据类型介绍 Go 语言中数据类型分为&#xff1a;基本数据类型和复合数据类型基本数据类型有&#xff1a; 整型、浮点型、布尔型、字符串复合数据类型有&#xff1a; 数组、切片、结构体、函数、map、通道&#xff08;channel&#xff09;、接口 2、…

Redux在React中的使用

Redux在React中的使用 1.构建方式 采用reduxjs/toolkitreact-redux的方式 安装方式 npm install reduxjs/toolkit react-redux2.使用 ①创建目录 创建store文件夹&#xff0c;然后创建index和对应的模块&#xff0c;如上图所示 ②编写counterStore.js 文章以counterStore…

C语言入门---位操作

目录 1. 两个数不同的二进制位个数 2.原码、反码、补码 3.不创建临时变量实现两个数的交换 4.求一个整数存储在内存中的二进制中1的个数 5. 特例-1 6.将指定的位置置1 7.将指定位置置1 8.a与a 9.||与&& 10.逗号表达式 11.srand与rand 12.sizeof 13.结构体初始…

时间序列预测实战(二十)自研注意力机制Attention-LSTM进行多元预测(结果可视化,自研结构)

一、本文介绍 本文给大家带来的是我利用我自研的结构进行Attention-LSTM进行时间序列预测&#xff0c;该结构是我专门为新手和刚入门的读者设计&#xff0c;包括结果可视化、支持单元预测、多元预测、模型拟合效果检测、预测未知数据、以及滚动长期预测&#xff0c;大家不仅可…

Vue框架学习笔记——侦听(监视)属性watch:天气案例+immediate+deep深度监听

文章目录 前文提要天气案例描述样例代码呈现效果&#xff1a;事件的响应中可以写一些简单的语句&#xff08;不推荐&#xff09; 侦听&#xff08;监视&#xff09;属性watch结合天气案例的第一种写法&#xff08;New Vue&#xff09;immediate&#xff1a; 侦听&#xff08;监…
最新文章