当前位置: 首页 > news >正文

C++参悟-单例模式

单例模式

  • 一、概述
    • 1. 特点
    • 2. 实现方式
    • 3. 应用场景
  • 二、实现代码
    • 1. 静态局部变量的懒汉单例
    • 2. 加锁的懒汉式单例
    • 3. 使用 C++11 中的 std::call_one 的懒汉单例
    • 4. 饿汉式单例

一、概述

这里记录一下单例模式的最常用使用,单例模式(Single Pattern)是一种常用的软件设计模式,它属于创建型模式。单例模式的定义是确保一个类仅有一个实例,并提供一个全局访问点来获取这个唯一的实例。该模式的核心在于控制实例的数目,使得在整个系统中,该类只被实例化一次。

1. 特点

  1. 单例类只能有一个实例:这是单例模式最基本的要求,确保类的全局唯一性。
  2. 单例类必须自行创建自己的唯一实例:这通常通过私有化构造函数来实现,防止外部通过new关键字直接创建实例。
  3. 单例类必须给所有其他对象提供这一实例:这通常通过一个静态的公有方法来实现,该方法负责返回类的唯一实例。

2. 实现方式

单例模式有多种实现方式,其中最典型的是懒汉式饿汉式

  1. 懒汉式:在真正需要使用对象时才去创建该单例类对象。这种方式在类加载时不会立即创建实例,而是在首次调用getInstance()方法时才创建,并通过加锁(如synchronized关键字)来保证多线程环境下的线程安全。但这种方式在多线程环境下存在性能问题,因为每次调用getInstance()方法时都需要进行同步判断。

  2. 饿汉式:在类加载时已经创建好该单例对象,等待程序使用。这种方式因为实例在类加载时就已经创建好了,所以不需要进行同步判断,是线程安全的。但这种方式在类加载时就占用了内存资源,如果单例对象体积较大或者类加载顺序不确定时,可能会浪费内存资源。

除了懒汉式和饿汉式外,还有枚举式、双重校验锁式、静态内部类式等多种单例模式的实现方式。这些方式各有优缺点,可以根据实际需求和场景选择适合的实现方式。

3. 应用场景

单例模式适用于以下场景:

  1. 全局唯一性:当需要控制某个类的实例数目为1时,可以使用单例模式。
  2. 共享资源:当多个对象需要共享一个资源时,可以将该资源设计为单例模式,以避免资源的重复创建和浪费。
  3. 配置信息:如应用程序的配置信息、全局缓存等,可以设计为单例模式,以便于全局访问和管理。

二、实现代码

1. 静态局部变量的懒汉单例

这个是线程安全的,因为静态局部变量的创建方式天然是线程安全的,不存在线程不安全的问题,我基本上只用这个

class Single {
public:static Single& GetInstance();			// 获取单实例对象void Print();							// 打印实例地址
private:    Single();								// 禁止外部构造~Single();								// 禁止外部析构Single(const Single &single) = delete;	// 禁止外部拷贝构造Single(const Single &&) = delete;		// 禁止右值拷贝构造const Single &operator=(const Single &single) = delete;	// 禁止外部赋值操作
};
Single& Single::GetInstance(){/*** 静态局部变量只在当前函数内有效,其他函数无法访问。* 静态局部变量只在第一次被调用的时候初始化,也存储在静态存储区,生命周期从第一次被初始化起至程序结束止。*/static Single single;return single;
}void Single::Print(){std::cout << "实例内存地址:" << this << std::endl;
}Single::Single() {std::cout << "构造函数" << std::endl;
}Single::~Single() {std::cout << "析构函数" << std::endl;
}

2. 加锁的懒汉式单例

加锁的懒汉式实现

class Single {
public:static Single *GetInstance();	// 获取单实例对象static void deleteInstance();	//释放单实例,进程退出时调用void Print();					// 打印实例地址
private:Single();						// 将其构造和析构成为私有的, 禁止外部构造和析构~Single();Single(const Single &signal);	// 将其拷贝构造和赋值构造成为私有函数, 禁止外部拷贝、赋值、右值拷贝构造Single(const Single &&) = delete;const Single &operator=(const Single &signal);
private:static Single *m_Single;		// 实例对象指针static std::mutex m_Mutex;		// 互斥锁
};
//初始化静态成员变量
Single *Single::m_Single = nullptr;
std::mutex Single::m_Mutex;// 注意:不能返回指针的引用,否则存在外部被修改的风险!
Single * Single::GetInstance(){//  这里使用了两个 if 判断语句的技术称为双检锁;好处是,只有判断指针为空的时候才加锁,//  避免每次调用 GetInstance的方法都加锁,锁的开销毕竟还是有点大的。if (m_Single == nullptr){std::unique_lock<std::mutex> lock(m_Mutex); // 加锁if (m_Single == nullptr){volatile auto temp = new (std::nothrow) Single();m_Single = temp;}}return m_Single;
}void Single::deleteInstance(){std::unique_lock<std::mutex> lock(m_Mutex); // 加锁if (m_Single){delete m_Single;m_Single = nullptr;}
}void Single::Print(){std::cout << "实例内存地址:" << this << std::endl;
}Single::Single(){std::cout << "构造函数" << std::endl;
}Single::~Single(){std::cout << "析构函数" << std::endl;
}

使用智能指针

#include <iostream>
#include <memory>
#include <mutex>class Single {
public:static std::shared_ptr<Single> GetInstance();void print() {std::cout << "Hello World." << std::endl;}~Single() {std::cout << "析构函数" << std::endl;}private:Single() {std::cout << "构造函数" << std::endl;}
};static std::shared_ptr<Single> Single = nullptr;
static std::mutex SingleMutex;std::shared_ptr<Single> Single::GetInstance() {if (Single == nullptr) {std::unique_lock<std::mutex> lock(SingleMutex);if (Single == nullptr) {volatile auto temp = std::shared_ptr<Single>(new Single());Single = temp;}}return Single;
}

3. 使用 C++11 中的 std::call_one 的懒汉单例

#include <iostream>
#include <memory>
#include <mutex>class Single {
public:static std::shared_ptr<Single> GetInstance();void print() {std::cout << "Hello World." << std::endl;}~Single() {std::cout << "析构函数" << std::endl;}private:Single() {std::cout << "构造函数" << std::endl;}
};static std::shared_ptr<Single> Single = nullptr;
static std::once_flag SingleFlag;std::shared_ptr<Single> Single::GetInstance() {std::call_once(SingleFlag, [&] {Single = std::shared_ptr<Single>(new Single());});return Single;
}

4. 饿汉式单例

class Singleton{
public:    static Singleton* GetInstance();		// 获取单实例static void deleteInstance();			// 释放单实例,进程退出时调用void Print();							// 打印实例地址
private:   Singleton();							// 将其构造和析构成为私有的, 禁止外部构造和析构~Singleton();Singleton(const Singleton &signal);		// 将其拷贝构造和赋值构造成为私有函数, 禁止外部拷贝和赋值Single(const Single &&) = delete;const Singleton &operator=(const Singleton &signal);private:    static Singleton *m_pSingleton;			// 单例指针
};
// 代码一运行就初始化创建实例 ,本身就线程安全
Singleton* Singleton::m_pSingleton = new (std::nothrow) Singleton();Singleton* Singleton::GetInstance(){return m_pSingleton;
}void Singleton::deleteInstance(){if (m_pSingleton)    {delete m_pSingleton;m_pSingleton = nullptr;}
}void Singleton::Print(){std::cout << "实例内存地址:" << this << std::endl;
}Singleton::Singleton(){std::cout << "构造函数" << std::endl;
}Singleton::~Singleton(){std::cout << "析构函数" << std::endl;
}

相关文章:

C++参悟-单例模式

单例模式 一、概述1. 特点2. 实现方式3. 应用场景 二、实现代码1. 静态局部变量的懒汉单例2. 加锁的懒汉式单例3. 使用 C11 中的 std::call_one 的懒汉单例4. 饿汉式单例 一、概述 这里记录一下单例模式的最常用使用&#xff0c;单例模式&#xff08;Single Pattern&#xff0…...

【题解】—— LeetCode一周小结32

&#x1f31f;欢迎来到 我的博客 —— 探索技术的无限可能&#xff01; &#x1f31f;博客的简介&#xff08;文章目录&#xff09; 【题解】—— 每日一道题目栏 上接&#xff1a;【题解】—— LeetCode一周小结31 5.不含连续1的非负整数 题目链接&#xff1a;600. 不含连续…...

详解线索分层的目的、维度与创新实践

线索分层是一个系统性的过程&#xff0c;旨在更有效地管理、跟踪和利用线索资源。这一过程可以借鉴多种策略和方法&#xff0c;特别是在用户运营和市场营销中。 1、线索分层的目的 线索分层的主要目的是根据线索的不同特征或成熟度&#xff0c;将其分类管理&#xff0c;以便更…...

于8月21号的回顾

傍晚的日落和逐渐深邃的夜&#xff0c;驱散了白天的极致闷热。倦怠和疲惫充斥着大脑&#xff0c;喧嚣的浮沉又在耳边轰鸣。 我不曾想到&#xff0c;再次打开博客已经是两年后的今天了。手指轻轻滑过鼠标&#xff0c;博客的页面缓缓加载&#xff0c;那些被时间尘封的记忆瞬间涌…...

Abstract Class抽象类

抽象类&#xff08;Abstract Class&#xff09;在面向对象编程中是一种特殊的类&#xff0c;它不能被实例化&#xff0c;即不能创建该类的对象。抽象类主要用于定义一组接口&#xff08;即方法&#xff09;&#xff0c;这些方法的具体实现由子类来完成。抽象类通常用于表示一种…...

webrtc ns 降噪之粉红噪声参数推导

webrtc中降噪中&#xff0c;前50帧需要进行简单噪声估计&#xff0c;使用白噪声和粉红噪声模型估算。 首先我们 复习 有色噪声&#xff08;包含白噪声&#xff09;的一般模型&#xff1a; S(f) 是频率 f 处的功率谱密度。f是频率。α 是一个频谱指数&#xff0c;通常在1左右。…...

IO进程线程8月21日

1&#xff0c;思维导图 2&#xff0c;登录 #ifndef __LOG_H__ #define __LOG_H__ #include<myhead.h> typedef struct {char name[20];char pwd[20]; }str;int regist();int login(); #endif#include"log.h" int login() {char a[20]"\n";str p,s;…...

Web安全:SqlMap工具

一、简介 sqlmap 是一款开源的渗透测试工具&#xff0c;可以自动化进行SQL注入的检测、利用&#xff0c;并能接管数据库服务器。它具有功能强大的检测引擎,为渗透测试人员提供了许多专业的功能并且可以进行组合&#xff0c;其中包括数据库指纹识别、数据读取和访问底层文件系统…...

用手机写一本电子书

第1步、进入Andi.cn网站 第2步、点击登录&#xff0c;注册用户 第3步、点击去创作&#xff0c;进入创作页面 第4步、点击右下角的小笔&#xff0c;写一篇文章 第5步、下翻&#xff0c;点击提交按钮 第6步、再写一篇文章 第7步、点击栏目设计 第8步、进入栏目设计&#xff0c;点…...

【网络编程】基于UDP的TFTP文件传输

1&#xff09;tftp协议概述 简单文件传输协议&#xff0c;适用于在网络上进行文件传输的一套标准协议&#xff0c;使用UDP传输 特点&#xff1a; 是应用层协议 基于UDP协议实现 数据传输模式 octet&#xff1a;二进制模式&#xff08;常用&#xff09; mail&#xff1a;已经不再…...

Vue 3 + Pinia 实现网页刷新功能

概述 在现代 Web 开发中&#xff0c;保持用户界面的动态性和响应性至关重要。当用户触发某些操作时&#xff0c;例如点击按钮或者完成表单提交&#xff0c;我们往往需要刷新页面的一部分来展示最新的数据。本文将介绍如何使用 Vue 3 和 Pinia 来实现这一功能。 技术栈 Vue 3…...

DVWA综合靶场漏洞讲解

目录 综合靶场漏洞讲解 Brute Force Low Medium High Command Injection Low Medium High File Inclusion Low,Medium,High File Upload Low Medium High SQL Injection Low Medium High SQL Injection (Blind) Low Medium High XSS&#xff08;DOM&am…...

实现Bezier样条曲线

1.给出n1 个控制点pk(xk,yk,zk),这里k可取值0-n,多项式函数公式如下 获取的单个点的代码 void zmBezier::getPoint(float u, double p[3]) {int n m_count - 1;double x 0, y 0, z 0;for(int k 0; k < n; k){x m_ctrlPoints[k][0] * BEZ_k_n(n, k, u);y m_ctrlPoin…...

MySQL中的EXPLAIN的详解

一、介绍 官网介绍&#xff1a; https://dev.mysql.com/doc/refman/5.7/en/explain-output.htmlhttps://dev.mysql.com/doc/refman/8.0/en/explain-output.htmlexplain&#xff08;执行计划&#xff09;&#xff0c;使用explain关键字可以模拟优化器执行sql查询语句&#xff…...

LearnOpenGL——SSAO学习笔记

LearnOpenGL——SSAO学习笔记 SSAO一、基本概念二、样本缓冲三、法向半球四、随机核心转动五、SSAO着色器六、环境遮蔽模糊七、应用SSAO遮蔽因子 SSAO 一、基本概念 环境光照是我们加入场景总体光照中的一个固定光照常量&#xff0c;它被用来模拟光的散射(Scattering)。散射应…...

[C语言]-基础知识点梳理-文件管理

前言 各位师傅们好&#xff0c;我是qmx_07&#xff0c;今天给大家讲解文件管理的相关知识&#xff0c;也就是常见的 读取&#xff0c;删除一类的操作 文件 为什么要使用文件&#xff1f; 程序的数据是存储在电脑的内存中&#xff0c;如果程序退出&#xff0c;内存回收&…...

pcdn闲置带宽被动收入必看教程。第五讲:光猫更换和基础设置

PCDN闲置带宽被动收入必看教程 —— 第五讲&#xff1a;光猫更换和基础设置 为了从闲置带宽中获得被动收入&#xff0c;高效的网络设备至关重要。运营商提供的光猫通常能满足日常家用需求&#xff0c;但对于PCDN应用来说&#xff0c;它们可能不足以提供所需的高性能和稳定性。…...

工业数据采集网关简介-天拓四方

随着工业4.0和物联网&#xff08;IoT&#xff09;技术的深入发展&#xff0c;工业数据采集网关作为连接现场设备与上层管理系统的关键节点&#xff0c;其在智能工厂中的作用愈发凸显。本文将深入探讨工业数据采集网关的功能、特点、应用场景及其实操性&#xff0c;以期为读者提…...

Java 调整字符串,验证码生成

package text7;public class ZiFanz {public static void main(String[] args) {//1.定义两个字符串String strA "abcde";String strB "deabc";//2.abcde->bcdea->cdeab->deabc旋转字符串//旋转并比较boolean result cheak(strA, strB);System…...

【专题】全球商用服务机器人市场研究(2023)报告合集PDF分享(附原数据表)

原文链接&#xff1a;https://tecdat.cn/?p37366 近年来&#xff0c;随着人工智能、物联网和自动化技术的不断进步&#xff0c;商用服务机器人行业迅速崛起&#xff0c;展现出广阔的发展前景。从最初的实验室研发到如今的规模化应用&#xff0c;商用服务机器人已逐渐成为各行…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力

引言&#xff1a; 在人工智能快速发展的浪潮中&#xff0c;快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型&#xff08;LLM&#xff09;。该模型代表着该领域的重大突破&#xff0c;通过独特方式融合思考与非思考…...

Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器

第一章 引言&#xff1a;语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域&#xff0c;文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量&#xff0c;支撑着搜索引擎、推荐系统、…...

Python爬虫(一):爬虫伪装

一、网站防爬机制概述 在当今互联网环境中&#xff0c;具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类&#xff1a; 身份验证机制&#xff1a;直接将未经授权的爬虫阻挡在外反爬技术体系&#xff1a;通过各种技术手段增加爬虫获取数据的难度…...

ABAP设计模式之---“简单设计原则(Simple Design)”

“Simple Design”&#xff08;简单设计&#xff09;是软件开发中的一个重要理念&#xff0c;倡导以最简单的方式实现软件功能&#xff0c;以确保代码清晰易懂、易维护&#xff0c;并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计&#xff0c;遵循“让事情保…...

论文笔记——相干体技术在裂缝预测中的应用研究

目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术&#xff1a;基于互相关的相干体技术&#xff08;Correlation&#xff09;第二代相干体技术&#xff1a;基于相似的相干体技术&#xff08;Semblance&#xff09;基于多道相似的相干体…...

从 GreenPlum 到镜舟数据库:杭银消费金融湖仓一体转型实践

作者&#xff1a;吴岐诗&#xff0c;杭银消费金融大数据应用开发工程师 本文整理自杭银消费金融大数据应用开发工程师在StarRocks Summit Asia 2024的分享 引言&#xff1a;融合数据湖与数仓的创新之路 在数字金融时代&#xff0c;数据已成为金融机构的核心竞争力。杭银消费金…...

PostgreSQL——环境搭建

一、Linux # 安装 PostgreSQL 15 仓库 sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-$(rpm -E %{rhel})-x86_64/pgdg-redhat-repo-latest.noarch.rpm# 安装之前先确认是否已经存在PostgreSQL rpm -qa | grep postgres# 如果存在&#xff0…...

车载诊断架构 --- ZEVonUDS(J1979-3)简介第一篇

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…...

负载均衡器》》LVS、Nginx、HAproxy 区别

虚拟主机 先4&#xff0c;后7...

DAY 45 超大力王爱学Python

来自超大力王的友情提示&#xff1a;在用tensordoard的时候一定一定要用绝对位置&#xff0c;例如&#xff1a;tensorboard --logdir"D:\代码\archive (1)\runs\cifar10_mlp_experiment_2" 不然读取不了数据 知识点回顾&#xff1a; tensorboard的发展历史和原理tens…...