单例模式 (Singleton Pattern)

单例模式 (Singleton Pattern) 是一种创建型设计模式,确保一个类只有一个实例,并提供一个全局访问点。

一、基础

1. 意图

  • 确保一个类只有一个实例。
  • 提供一个全局访问点。

2. 适用场景

  • 一个类只需要一个实例来协调系统行为时,例如数据库连接池,线程池、缓存、日志对象等。
  • 需要控制实例数目,节省系统资源,避免重复创建和浪费, 同时保证数据的一致性和正确性。

3. 结构

  • 一个静态成员变量
  • 一个私有构造函数
  • 一个静态方法

二、进阶

1. 线程安全

  • 饿汉式: 在类加载时就创建实例,线程安全,但可能会造成资源浪费。
  • 懒汉式: 在第一次调用 getInstance() 时才创建实例,需要考虑线程安全问题。
  • 双重检查锁定: 使用 volatile 关键字和 synchronized 关键字来保证线程安全。
  • 静态内部类: 利用类加载机制保证线程安全。

2. 序列化与反序列化

  • 在 C++ 中,并没有像 Java 那样内置的序列化机制。但是,如果使用第三方库(如 Boost.Serialization)进行序列化和反序列化操作,同样需要注意单例模式的问题。在反序列化时,可能会创建新的实例对象,破坏单例模式。为了避免这种情况,可以在反序列化过程中进行特殊处理,确保返回的是已经存在的单例实例。

3. 反射攻击

  • 为了防止反射调用私有构造函数创建新的实例,可以在构造函数中进行判断。

三、关键点

1. 私有构造函数:单例类的构造函数必须是私有的,以防止外部通过new关键字实例化对象,确保只有一个实例对象存在。

2. 静态实例变量:单例类中必须有一个静态的实例变量来保存唯一的实例对象,并且该实例变量的作用域必须是私有的,以防止外部直接访问和修改。

3. 公共静态访问方法:提供一个公共的静态方法,作为全局访问点,用于获取单例对象的实例。该方法通常命名为getInstance()。

4. 线程安全:在多线程环境下,单例模式的实现必须保证线程安全,确保在任何情况下都只会创建一个实例对象。常见的线程安全实现方式有同步方法、双重检查锁定、静态局部变量等。

5. 延迟加载:对于某些应用场景,延迟加载(懒汉式)是非常重要的,它可以避免在程序启动时就创建不必要的实例对象,从而提高系统性能和资源利用率。但需要注意的是,懒汉式实现需要处理好线程安全问题。

四、易错点

1. 线程安全问题:在实现懒汉式单例模式时,如果不注意线程安全,很容易导致在多线程环.          境下创建多个实例对象,违反单例模式的定义。例如,在没有同步机制的情况下,多个线程同时.   调用getInstance()方法,并且此时instance为nullptr,就会创建多个实例对象。

2. 序列化与反序列化:当使用第三方库进行序列化和反序列化操作时,如果不处理好单例模式的问题,可能会导致在反序列化时创建新的实例对象,破坏单例模式。需要在反序列化过程中进行特殊处理,确保返回的是已经存在的单例实例。

3. 反射破坏:虽然 C++ 没有像 Java 那样强大的反射机制,但是通过一些技术手段也可以实现类似反射的功能。如果不小心使用这些技术调用了单例类的私有构造函数,同样会破坏单例模式。为了防止这种情况,需要在构造函数中添加逻辑判断,防止重复创建实例对象。

4. 指令重排:在使用双重检查锁定实现线程安全的懒汉式单例模式时,需要注意编译器和处理器的指令重排问题。虽然 C++11 标准中引入了内存模型来解决这个问题,但是在一些老版本的编译器或者特定的硬件平台上,仍然可能存在指令重排导致的线程安全问题。

五、核心代码

1. 饿汉式

饿汉式是单例模式中最简单的一种实现方式。在程序启动时,就立即创建唯一的实例对象,并且该实例对象是静态的,因此在程序的整个生命周期中只会存在一个实例。

优点:实现简单,线程安全,因为在程序启动时就创建了实例,不存在多线程并发创建的问题。

缺点:如果该单例对象在整个应用程序中不一定会被使用到,那么在程序启动时就创建实例可能会造成资源浪费。

class Singleton {
private:static Singleton* instance;Singleton() {} // 私有构造函数public:static Singleton* getInstance() {return instance;}
};Singleton* Singleton::instance = new Singleton(); // 类加载时创建实例

2. 懒汉式 (双重检查锁定)

双重检查锁定(Double-Checked Locking)是一种优化的线程安全懒汉式实现方式。它通过两次检查instance是否为nullptr,在保证线程安全的同时提高了性能。

优点:延迟加载,只有在真正需要使用单例对象时才创建,避免了不必要的资源浪费。既实现了线程安全,又提高了性能。在第一次检查instance为nullptr时,只有一个线程能够进入同步块,在同步块内再次检查instance为nullptr时才创建实例对象,避免了每次调用getInstance()方法都获取锁的性能开销。

缺点:实现相对复杂,需要理解双重检查锁定的原理以及互斥锁的使用。

class Singleton {
private:static Singleton* instance;static std::mutex mtx;Singleton() {} // 私有构造函数public:static Singleton* getInstance() {if (instance == nullptr) {std::lock_guard<std::mutex> lock(mtx);if (instance == nullptr) {instance = new Singleton();}}return instance;}
};Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;

3. 懒汉式 (静态内部类)

在 C++11 之后,可以利用静态局部变量的特性来实现单例模式,这种方式既实现了延迟加载,又保证了线程安全。

优点:延迟加载,线程安全。由于静态局部变量在第一次调用getInstance()方法时才会被初始化,因此实现了延迟加载。同时,C++11 标准保证了静态局部变量的初始化是线程安全的。

缺点:无明显缺点。

class Singleton {
private:Singleton() {} // 私有构造函数static class SingletonHolder {public:static Singleton* instance;};public:static Singleton* getInstance() {return SingletonHolder::instance;}
};

4. 防止序列化与反序列化

class Singleton {
private:static Singleton* instance;Singleton() {} // 私有构造函数public:static Singleton* getInstance() {if (instance == nullptr) {instance = new Singleton();}return instance;}// 防止反序列化创建新的实例Singleton* readResolve() {return getInstance();}
};Singleton* Singleton::instance = nullptr;

5. 防止反射攻击

class Singleton {
private:static Singleton* instance;Singleton() {if (instance != nullptr) {throw std::runtime_error("Singleton instance already exists!");}} // 私有构造函数public:static Singleton* getInstance() {if (instance == nullptr) {instance = new Singleton();}return instance;}
};Singleton* Singleton::instance = nullptr;

六、总结

单例模式是一种常用的设计模式,但需要注意线程安全、序列化与反序列化、反射攻击等问题。在实际开发中,需要根据具体需求选择合适的实现方式。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《TCP/IP网络编程》学习笔记 | Chapter 18:多线程服务器端的实现

《TCP/IP网络编程》学习笔记 | Chapter 18&#xff1a;多线程服务器端的实现 《TCP/IP网络编程》学习笔记 | Chapter 18&#xff1a;多线程服务器端的实现线程的概念引入线程的背景线程与进程的区别 线程创建与运行pthread_createpthread_join可在临界区内调用的函数工作&#…

C++相关基础概念之入门讲解(上)

1. 命名空间 C中的命名空间&#xff08;namespace&#xff09;是用来避免命名冲突问题的一种机制。通过将类、函数、变量等封装在命名空间中&#xff0c;可以避免不同部分的代码中出现相同名称的冲突。在C中&#xff0c;可以使用namespace关键字来定义命名空间。 然后我们在调…

创新技术引领软件供应链安全,助力数字中国建设

编者按 随着数字化转型的加速&#xff0c;针对软件供应链的攻击事件呈快速增长态势&#xff0c;目前已成为网络空间安全的焦点。如何将安全嵌入到软件开发到运营的全流程&#xff0c;实现防护技术的自动化、一体化、智能化&#xff0c;成为技术领域追逐的热点。 悬镜安全作为…

PyTorch 系列教程:使用CNN实现图像分类

图像分类是计算机视觉领域的一项基本任务&#xff0c;也是深度学习技术的一个常见应用。近年来&#xff0c;卷积神经网络&#xff08;cnn&#xff09;和PyTorch库的结合由于其易用性和鲁棒性已经成为执行图像分类的流行选择。 理解卷积神经网络&#xff08;cnn&#xff09; 卷…

【2025】基于python+django的驾校招生培训管理系统(源码、万字文档、图文修改、调试答疑)

课题功能结构图如下&#xff1a; 驾校招生培训管理系统设计 一、课题背景 随着机动车保有量的不断增加&#xff0c;人们对驾驶技能的需求也日益增长。驾校作为驾驶培训的主要机构&#xff0c;面临着激烈的市场竞争和学员需求多样化等挑战。传统的驾校管理模式往往依赖于人工操作…

【JavaWeb】快速入门——HTMLCSS

文章目录 一、 HTML简介1、HTML概念2、HTML文件结构3、可视化网页结构 二、 HTML标签语法1、标题标签2、段落标签3、超链接4、换行5、无序列表6、路径7、图片8、块1 盒子模型2 布局标签 三、 使用HTML表格展示数据1、定义表格2、合并单元格横向合并纵向合并 四、 使用HTML表单收…

MySQL 优化方案

一、MySQL 查询过程 MySQL 查询过程是指从客户端发送 SQL 语句到 MySQL 服务器&#xff0c;再到服务器返回结果集的整个过程。这个过程涉及多个组件的协作&#xff0c;包括连接管理、查询解析、优化、执行和结果返回等。 1.1 查询过程的关键组件 连接管理器&#xff1a;管理…

服务性能防腐体系:基于自动化压测的熔断机制

01# 背景 在系统架构的演进过程中&#xff0c;项目初始阶段都会通过压力测试构建安全护城河&#xff0c;此时的服务性能与资源水位保持着黄金比例关系。然而在业务高速发展时期&#xff0c;每个冲刺周期都被切割成以业务需求为单位的开发单元&#xff0c;压力测试逐渐从必选项…

六十天前端强化训练之第二十天React Router 基础详解

欢迎来到编程星辰海的博客讲解 看完可以给一个免费的三连吗&#xff0c;谢谢大佬&#xff01; 目录 一、核心概念 1.1 核心组件 1.2 路由模式对比 二、核心代码示例 2.1 基础路由配置 2.2 动态路由示例 2.3 嵌套路由实现 2.4 完整示例代码 三、关键功能实现效果 四、…

grad_traj_optimization 开源项目

开源项目 grad_traj_optimization 使用教程-CSDN博客 ubuntu如何切换到root用户_ubuntu切换到root用户-CSDN博客 catkin_make: command not found 解决办法_catkin-make not found-CSDN博客 这就说明需要编译的package虽然存在&#xff0c;但不在指定的目录下。catkin_make命…

深圳南柯电子|净水器EMC测试整改:水质安全与电磁兼容性的双赢

在当今注重健康生活的时代&#xff0c;净水器作为家庭用水安全的第一道防线&#xff0c;其性能与安全性备受关注。其中&#xff0c;电磁兼容性&#xff08;EMC&#xff09;测试是净水器产品上市前不可或缺的一环&#xff0c;它直接关系到产品在复杂电磁环境中的稳定运行及不对其…

要登录的设备ip未知时的处理方法

目录 1 应用场景... 1 2 解决方法&#xff1a;... 1 2.1 wireshark设置... 1 2.2 获取网口mac地址&#xff0c;wireshark抓包前预过滤掉自身mac地址的影响。... 2 2.3 pc网口和设备对接... 3 2.3.1 情况1&#xff1a;... 3 2.3.2 情…

GHCTF web方向题解

upload?SSTI! import os import refrom flask import Flask, request, jsonify,render_template_string,send_from_directory, abort,redirect from werkzeug.utils import secure_filename import os from werkzeug.utils import secure_filenameapp Flask(__name__)# 配置…

Vision Transformer (ViT):将Transformer带入计算机视觉的革命性尝试(代码实现)

Vision Transformer (ViT)&#xff1a;将Transformer带入计算机视觉的革命性尝试 作为一名深度学习研究者&#xff0c;如果你对自然语言处理&#xff08;NLP&#xff09;领域的Transformer架构了如指掌&#xff0c;那么你一定不会对它在序列建模中的强大能力感到陌生。然而&am…

蓝耘携手通义万象 2.1 图生视频:开启创意无限的共享新时代

在科技飞速发展的今天&#xff0c;各种新奇的技术不断涌现&#xff0c;改变着我们的生活和工作方式。蓝耘和通义万象 2.1 图生视频就是其中两项非常厉害的技术。蓝耘就像是一个超级大管家&#xff0c;能把各种资源管理得井井有条&#xff1b;而通义万象 2.1 图生视频则像是一个…

IEC61850标准下MMS 缓存报告控制块 ResvTms详细解析

IEC61850标准是电力系统自动化领域唯一的全球通用标准。IEC61850通过标准的实现&#xff0c;使得智能变电站的工程实施变得规范、统一和透明&#xff0c;这大大提高了变电站自动化系统的技术水平和安全稳定运行水平。 在 IEC61850 标准体系中&#xff0c;ResvTms&#xff08;r…

【DeepSeek应用】DeepSeek模型本地化部署方案及Python实现

DeepSeek实在是太火了,虽然经过扩容和调整,但反应依旧不稳定,甚至小圆圈转半天最后却提示“服务器繁忙,请稍后再试。” 故此,本文通过讲解在本地部署 DeepSeek并配合python代码实现,让你零成本搭建自己的AI助理,无惧任务提交失败的压力。 一、环境准备 1. 安装依赖库 …

蓝思科技冲刺港股上市,双重上市的意欲何为?

首先&#xff0c;蓝思科技冲刺港股上市&#xff0c;这一举措是其国际化战略进入实质性阶段的重要标志。通过港股上市&#xff0c;蓝思科技有望进一步拓宽融资渠道&#xff0c;这不仅能够为公司带来更加多元化的资金来源&#xff0c;还能够降低对单一市场的依赖风险&#xff0c;…

深入探讨RAID 5的性能与容错能力:实验与分析(磁盘阵列)

前言—— 本实验旨在探讨 RAID 5 的性能和容错能力。通过创建 RAID 5 阵列并进行一系列读写性能测试及故障模拟&#xff0c;我们将观察 RAID 5 在数据冗余和故障恢复方面的表现&#xff0c;以验证其在实际应用中的可靠性和效率。 首先说明&#xff1a;最少三块硬盘, 使用 4 块…

excel中两个表格的合并

使用函数&#xff1a; VLOOKUP函数 如果涉及在excel中两个工作表之间进行配对合并&#xff0c;则&#xff1a; VLOOKUP(C1,工作表名字!A:B,2,0) 参考&#xff1a; excel表格中vlookup函数的使用方法步骤https://haokan.baidu.com/v?pdwisenatural&vid132733503560775…