C++单例模式的实现
单例模式就是在整个程序运行期都只有一个实例。在代码实现方面,我们要限制new出多于一个对象这种情况的发生。而不是仅仅依靠无保障的约定。
目前大多数的编程语言的做法都是私有化构造函数,对外提供一个获取实例的接口。这样做的目的使实例的创建不能在类外部完成,这样我们只需要在内部保障实例只创建一次即可。我们用一个例子来说明C++的单例:
#include <iostream>
using namespace std;class TestCls{private:TestCls(){} // 构造函数私有化,在外部就无法通过new运算符创建新实例// 声明单例里的指针,static的成员在这里只是声明,它的初始化还没有完成static TestCls *m_instance;public:~TestCls(){//析构函数cout << "TestCls is destroying" << endl;}// 对外暴露一个接口获得单例static TestCls* getinstance(){if(m_instance == NULL){// new出来的对象,一定要用delete运算符删除对应的指针m_instance = new TestCls();// 巧妙的地方static MyGC mygc;}return m_instance;}void test(){cout << "test" << endl;}// 在单例里再定义一个内部类class MyGC {public:~MyGC(){//在内部类的析构函数里delete掉单例if(TestCls::m_instance){delete TestCls::m_instance;TestCls::m_instance = NULL;}}};
};// static 成员的初始化
TestCls * TestCls::m_instance = NULL;int main(){//获取单例TestCls * ptr = TestCls::getinstance();cout << ptr << endl;ptr = TestCls::getinstance();cout << ptr <<endl;return 0;
}
定义单例基本上来说是很简单的,就是先私有化构造函数,单例内部new出这个实例,并对外提供获取实例的接口。在这里我想特别分享一下,为什么要弄一个内部类的作用。
目的只有一个就是当程序退出时主动delete掉实例。其次new出来的指针要主动delete掉,malloc出来的东西要主动free掉,这些是编程的好习惯。
我在new出单例时,初始化一个内部类static MyGC mygc; 带上static关键字后,它的生命周期会一直持续到程序退出,因为这个对象不是new也不是malloc出来的,所有它就不会在堆内存里,它会在静态代码区,而单例是new出来的它就在堆内存里。在程序退出时,就会调用内部类的析构函数,这样我们就可以借此delete掉单例。这是一个很巧妙的使用。
C++单例的增强
前面的代码中我们可以看到每个线程调用getinstance()都会先判断是否空,是的话就new一个新的实例。实际上,我们可以改进一下这段代码,C++11提供了call_once的功能,就是说这个功能可以让某个函数只被调用一次。那么我们可以将创建单例的代码,抽象成一个方法,并使用这个方法只被调用一次,这能给我们带来什么好处呢?
我们上面的代码可能没有解决好在多线程中,这个单例的初始化需要互斥的问题。也就是说可能存在多个线程在同时初始化这个实例。一般的做法就是给初始化的代码块加锁,即:
m_mutex.lock();
if(m_instance == NULL){m_instance = new TestCls();static MyGC mygc;
}
m_mutex.unlock();
现在用c++11提供的call_once函数功能就可以轻松解决这个初始化需要互斥的问题。调整过的部分:
once_flag gflag;
class TestCls{private:...static void createinstance(){if(m_instance == NULL) {m_instance = new TestCls();static MyGC mygc;}}public:...static TestCls* getinstance(){call_once(gflag,createinstance);return m_instance;}......
};
我们还可以再提高一些效率:
once_flag gflag;
class TestCls{private:...static void createinstance(){if(m_instance == NULL) {m_instance = new TestCls();static MyGC mygc;}}public:...static TestCls* getinstance(){if(m_instance == NULL) { // 进一步提高效率call_once(gflag,createinstance);}return m_instance;}......
};
相关文章:
C++单例模式的实现
单例模式就是在整个程序运行期都只有一个实例。在代码实现方面,我们要限制new出多于一个对象这种情况的发生。而不是仅仅依靠无保障的约定。 目前大多数的编程语言的做法都是私有化构造函数,对外提供一个获取实例的接口。这样做的目的使实例的创建不能在…...
rust函数 stuct struct方法 关联函数
本文结合2个代码实例主要介绍了rust函数定义方法,struct结构体定义、struct方法及关联函数等相关基础知识。 代码1: main.rc #[derive(Debug)]//定义一个结构体 struct Ellipse {max_semi_axis: u32,min_semi_axis: u32, }fn main() {//椭圆࿰…...
浅谈基于中台模式的大数据生态体系的理解
这篇文章主要浅谈一下我对大数据生态体系建设的理解。 大数据生态系统为高并发,高吞吐,高峰值,高堆积等大规模数据的采集,处理,计算,存储,服务提供了完善的处理体系,致力于打造核心数…...
MySQL的锁机制
一:概述 锁是计算机协调多个进程或线程并发访问某一资源的机制(避免争抢); 在数据库中,除传统的计算资源(如CPU,RAM,I/O等)的争用以外,数据也是一种供许多用…...
已解决ImportError: cannot import name ‘PILLOW_VERSION‘异常的正确解决方法,亲测有效!!!
已解决ImportError: cannot import name PILLOW_VERSION异常的正确解决方法,亲测有效!!! 文章目录 问题分析 报错原因 解决思路 解决方法 总结 在Python项目开发中,依赖管理是保证项目正常运行的关键环节。然而&…...
力扣:300. 最长递增子序列
动态规划: 1. 先定义dp数组来表示在下标为i时最长递增子序列,先初始化一下每个下标的值为dp【i】1。同时我们要判断在下标i之前的最长的递增子序列为多少,在判断当前的下标i是否满足递增的条件满足的话就进行dp【i】的重新赋值。之后要更新接受的最长递…...
Swing程序设计(10)列表框,文本框,文本域,密码框
文章目录 前言一、列表框二、文本框(域) 1.文本框2.文本域三、密码框总结 前言 该篇文章简单介绍了Java中Swing组件里的列表框、文本框、密码框。 一、列表框 列表框(JList)相比下拉框,自身只是在窗体上占据固定的大小…...
【Java八股面试系列】JVM-常见参数设置
目录 堆内存相关 显式指定堆内存–Xms和-Xmx 显式新生代内存(Young Generation) 显式指定永久代/元空间的大小 垃圾收集相关 垃圾回收器 GC 日志记录 处理 OOM JDK监控和故障处理工具总结 堆内存相关 Java 虚拟机所管理的内存中最大的一块,Java 堆是所有线…...
【Python--Web应用框架大比较】
🚀 作者 :“码上有前” 🚀 文章简介 :Python 🚀 欢迎小伙伴们 点赞👍、收藏⭐、留言💬 Django Django太重了,除了web框架,自带ORM和模板引擎,灵活和自由度不…...
Effective Objective-C 学习第三周
理解引用计数 Objective-C 使用引用计数来管理内存:每个对象都有个可以递增或递减的计数器。如果想使某个对象继续存活,那就递增其引用计数:用完了之后,就递减其计数。计数变为 0时,就可以把它销毁。 在ARC中…...
人工智能学习与实训笔记(四):神经网络之NLP基础—词向量
人工智能专栏文章汇总:人工智能学习专栏文章汇总-CSDN博客 本篇目录 四、自然语言处理 4.1 词向量 (Word Embedding) 4.1.1 词向量的生成过程 4.1.2 word2vec介绍 4.1.3 word2vec:skip-gram算法的实现 4.2 句向量 - 情感分析 4.2.1 LSTM (Long S…...
【教程】Kotlin语言学习笔记(一)——认识Kotlin(持续更新)
写在前面: 如果文章对你有帮助,记得点赞关注加收藏一波,利于以后需要的时候复习,多谢支持! 【Kotlin语言学习】系列文章 第一章 《认识Kotlin》 文章目录 【Kotlin语言学习】系列文章一、Kotlin介绍二、学习路径 一、…...
MySQL性能分析1
1、查看执行频次 查看当前数据库的INSERT,UPDATE,DELETE,SELECT的访问频次,得到当前数据库是以插入,更新和删除为主还是以查询为主,如果是以插入,更新和删除为主的话,那么优化比重可以轻一点儿。 语法: …...
四、案例 - Oracle数据迁移至MySQL
Oracle数据迁移至MySQL 一、生成测试数据表和数据1.在Oracle创建数据表和数据2.在MySQL创建数据表 二、生成模板文件1.模板文件内容2.模板文件参数详解2.1 全局设置2.2 数据读取(Reader)2.3 数据写入(Writer)2.4 性能设置 三、案例…...
ABC340 A-F题解
文章目录 A题目AC Code: B题目AC Code: C题目AC Code: D题目AC Code: E题目思路做法时间复杂度AC Code: F题目思路AC Code: A 题目 模拟即可,会循环都能写。 AC Code: #include …...
微软 CMU - Tag-LLM:将通用大语言模型改用于专业领域
文章目录 一、前言二、主要内容三、总结 🍉 CSDN 叶庭云:https://yetingyun.blog.csdn.net/ 一、前言 论文地址:https://arxiv.org/abs/2402.05140 Github 地址:https://github.com/sjunhongshen/Tag-LLM 大语言模型(…...
Kafka集群安装与部署
集群规划 准备工作 安装 安装包下载:链接:https://pan.baidu.com/s/1BtSiaf1ptLKdJiA36CyxJg?pwd6666 Kafka安装与配置 1、上传并解压安装包 tar -zxvf kafka_2.12-3.3.1.tgz -C /opt/moudle/2、修改解压后的文件名称 mv kafka_2.12-3.3.1/ kafka…...
C++初阶(十一) list
一、list的介绍及使用 1.1 list的介绍 list的文档介绍 1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。 2. list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点…...
图像卷积、步长、填充、特征图、多通道卷积、权重共享、感受野、池化
图像卷积、步长、填充、特征图、多通道卷积、权重共享、感受野、池化 卷积神经网络的一些基本概念:图像卷积、步长、填充、特征图、多通道卷积、权重共享、感受野、池化 1.图像卷积、步长、填充 图像卷积:卷积核矩阵在一个原始图像矩阵上 “从上往下、…...
CMake进行C/C++与汇编混合编程
1. 前提 这篇文章记录一下怎么用CMake进行项目管理, 并用C/C和汇编进行混合编程, 为了使用这项技术, 必须在VS的环境中安装好cmake组件 由于大部分人不会使用C/C与汇编进行混合编程的情况。所以这篇文章并不适用于绝大部分人不会对其中具体细节进行过多叙述。只是做一些简单的…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...
突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...
C++八股 —— 单例模式
文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全(Thread Safety) 线程安全是指在多线程环境下,某个函数、类或代码片段能够被多个线程同时调用时,仍能保证数据的一致性和逻辑的正确性…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...
AGain DB和倍数增益的关系
我在设置一款索尼CMOS芯片时,Again增益0db变化为6DB,画面的变化只有2倍DN的增益,比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析: 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...
JavaScript基础-API 和 Web API
在学习JavaScript的过程中,理解API(应用程序接口)和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能,使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...
第7篇:中间件全链路监控与 SQL 性能分析实践
7.1 章节导读 在构建数据库中间件的过程中,可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中,必须做到: 🔍 追踪每一条 SQL 的生命周期(从入口到数据库执行)&#…...
基于Java+VUE+MariaDB实现(Web)仿小米商城
仿小米商城 环境安装 nodejs maven JDK11 运行 mvn clean install -DskipTestscd adminmvn spring-boot:runcd ../webmvn spring-boot:runcd ../xiaomi-store-admin-vuenpm installnpm run servecd ../xiaomi-store-vuenpm installnpm run serve 注意:运行前…...
