C++单例模式实现

单例模式(Singleton Pattern)是软件设计模式中的一种,用于确保一个类只有一个实例,并提供一个全局访问点来获取这个实例。

一、初始版本(手动创建释放)

一个类只有一个实例的实现方法:

  • 隐藏构造函数,是外界无法创造对象
  • 通过类静态成员函数getInstance返回静态局部对象指针(指向堆空间的指针数据成员),确保对象生命周期和程序一致,并且在程序中唯一
  • 使用destory释放堆空间
#include <iostream>
using std::cout;
using std::endl;class Singleton{
public:static Singleton *getInstance(){if(_pInstance==nullptr){_pInstance=new Singleton();}return _pInstance;}static void destory(){if(_pInstance){delete _pInstance;_pInstance=nullptr;}}
private:Singleton(){}static Singleton *_pInstance;int data;};
Singleton *Singleton::_pInstance=nullptr;
int main()
{cout<<Singleton::getInstance()<<endl;cout<<Singleton::getInstance()<<endl;Singleton::destory();return 0;
}

缺点:

需要人为手动释放堆空间,容易疏忽造成内存泄露

二、RAII思想

RAII(Resource Acquisition Is Initialization)是一种编程思想,主要用于C++等需要手动管理资源的语言中。RAII的核心思想是将资源的生命周期与对象的生命周期绑定,通过对象的构造函数来获取资源,通过析构函数来释放资源。这样做的好处是,当对象超出作用域并被销毁时,其析构函数会自动被调用,从而释放资源,避免了内存泄漏和其他资源泄露的问题。

RAII的主要特点包括:

  • 资源获取即初始化:在对象构造时获取所需的资源,如内存、文件句柄、网络连接等。
  • 自动资源释放:对象在超出作用域后自动调用析构函数,释放在构造函数中获取的资源。

三、利用RAII思想实现自动释放

 1、利用另一个对象的生命周期管理资源

#include <iostream>
using std::cout;
using std::endl;
class Singleton;class Singleton{
public:static Singleton *getInstance(){if(_pInstance==nullptr){_pInstance=new Singleton();}return _pInstance;}static void destory(){if(_pInstance){delete _pInstance;_pInstance=nullptr;}}
private:Singleton(){}static Singleton *_pInstance;int data;};
Singleton *Singleton::_pInstance=nullptr;
class AutoRelease{
public:AutoRelease(){}~AutoRelease(){Singleton::destory();}
};
int main()
{AutoRelease autoRls=AutoRelease();cout<<Singleton::getInstance()<<endl;cout<<Singleton::getInstance()<<endl;return 0;
}

缺点:仍然需要手动做额外的事情。

改进:嵌套类

2、嵌套类

Singleton中嵌套AutoRelease类,定义一个静态的AutoRelease成员_ar,创建Singleton对象自动产生一个AutoRelease对象,程序结束时会销毁全局静态区中的_ar,调用AutoRelease的析构函数,释放资源。

#include <iostream>
using std::cout;
using std::endl;class Singleton{
public:static Singleton *getInstance(){if(_pInstance==nullptr){_pInstance=new Singleton();}return _pInstance;}static void destory(){if(_pInstance){delete _pInstance;_pInstance=nullptr;}}
private:class AutoRelease{public:AutoRelease(){}~AutoRelease(){destory();}};Singleton(){}static Singleton *_pInstance;int data;static AutoRelease _ar;
};
Singleton *Singleton::_pInstance=nullptr;
Singleton::AutoRelease Singleton::_ar;
int main()
{cout<<Singleton::getInstance()<<endl;cout<<Singleton::getInstance()<<endl;return 0;
}

四、使用atexit函数释放资源

atexit 函数是 C 语言标准库中的一个函数,用于在程序正常退出时注册一个函数,以便在程序结束时自动调用。

int atexit(void (*function)(void));
  • function 参数是一个函数指针,指向一个不带参数且没有返回值的函数 
#include <iostream>
using std::cout;
using std::endl;class Singleton{
public:static Singleton *getInstance(){if(_pInstance==nullptr){_pInstance=new Singleton();}return _pInstance;}static void destory(){if(_pInstance){delete _pInstance;_pInstance=nullptr;}}
private:Singleton(){atexit(destory);}static Singleton *_pInstance;int data;};
Singleton *Singleton::_pInstance=nullptr;
int main()
{cout<<Singleton::getInstance()<<endl;cout<<Singleton::getInstance()<<endl;return 0;
}

五、线程安全

以上实现方式均为懒汉式,在多线程情况下可能会创建多个堆空间,而_pInstance只能指向一个,造成内存泄露。

Singleton *Singleton::_pInstance=nullptr;//懒汉式

可以使用饿汉式在程序最开始就创建,但这样可能带来内存压力。

Singleton *Singleton::_pInstance=getInstance();

使用pthread_once和atexit保障初始化代码只执行一次 ,实现线程安全

pthread_once 是 POSIX 线程库中的一个函数,用于在多线程环境中确保某个初始化函数只执行一次。这个函数特别有用,当你需要在程序启动时进行一些初始化操作,但又希望这些操作只执行一次,即使有多个线程同时尝试执行它们。

int pthread_once(pthread_once_t *once_control, void (*init_routine)(void));
  • once_control 是一个控制变量,必须指向一个初始化为 PTHREAD_ONCE_INIT 的 pthread_once_t 类型的静态或全局变量。
  • init_routine 是一个函数指针,指向一个不带参数且没有返回值的函数,这个函数包含了初始化代码。
#include <iostream>
#include<pthread.h>
using std::cout;
using std::endl;class Singleton{
public:static Singleton *getInstance(){pthread_once(&_once,init);return _pInstance;}static void init(){_pInstance=new Singleton();atexit(destory);}static void destory(){if(_pInstance){delete _pInstance;_pInstance=nullptr;}}
private:Singleton(){}static Singleton *_pInstance;int data;static pthread_once_t _once;
};
Singleton *Singleton::_pInstance=nullptr;
pthread_once_t Singleton::_once=PTHREAD_ONCE_INIT;int main()
{cout<<Singleton::getInstance()<<endl;cout<<Singleton::getInstance()<<endl;return 0;
}

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

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

相关文章

超好用shell脚本NuShell mac安装

利用管道控制任意系统 Nu 可以在 Linux、macOS 和 Windows 上运行。一次学习&#xff0c;处处可用。 一切皆数据 Nu 管道使用结构化数据&#xff0c;你可以用同样的方式安全地选择&#xff0c;过滤和排序。停止解析字符串&#xff0c;开始解决问题。 强大的插件系统 具备强…

OpenJudge_ 简单英文题_04:0/1 Knapsack

题目 描述 Given the weights and values of N items, put a subset of items into a knapsack of capacity C to get the maximum total value in the knapsack. The total weight of items in the knapsack does not exceed C. 输入 First line: two positive integers N (…

算法训练(leetcode)二刷第二十六天 | *452. 用最少数量的箭引爆气球、435. 无重叠区间、*763. 划分字母区间

刷题记录 *452. 用最少数量的箭引爆气球435. 无重叠区间*763. 划分字母区间笨拙版进阶版 *452. 用最少数量的箭引爆气球 leetcode题目地址 先对气球的坐标按照Xstart进行升序排序&#xff0c;只要两个气球之间挨着就可以一箭射穿&#xff0c;因此排序后查看后一个气球的起始坐…

第12章 系统部署

12.1 Kickstart使用背景介绍 随着公司业务不断增加,经常需要采购新服务器,并要求安装Linux系统,并且要求Linux版本要一致,方便以后的维护和管理,每次人工安装linux系统会浪费掉更多时间,如果我们有办法能节省一次一次的时间岂不更好呢? 大中型互联网公司一次采购服务器…

深入探讨LINQ中的数据分块(Chunk)方法及其应用

LINQ作为C#的核心特性之一&#xff0c;大大简化了数据操作的复杂性。它不仅能够通过声明式的语法进行数据查询&#xff0c;还能实现复杂的数据操作&#xff0c;比如筛选、排序、分组等。而在众多LINQ操作中&#xff0c;Chunk方法作为一种数据分块功能&#xff0c;能够让开发者更…

【Window主机访问Ubuntu从机——Xrdp配置与使用】

使用Xrdp在Window环境下远程桌面访问Ubuntu主机 文章目录 Ubuntu安装图形化界面Ubuntu安装Xrdp通过网线连接两台主机Window主机有线连接配置Ubuntu从机设置测试有线连接 Window主机打开远程桌面功能参考文章总结 Ubuntu安装图形化界面 sudo apt update sudo apt upgrade sudo …

ECharts图表图例8

用eclipse软件制作动态单仪表图 用java知识点 代码截图&#xff1a;

实验6记录网络与故障排除

实验6记录网络与故障排除 实验目的及要求&#xff1a; 通过实验&#xff0c;掌握如何利用文档记录网络设备相关信息并完成网络拓扑结构的绘制。能够使用各种技术和工具来找出连通性问题&#xff0c;使用文档来指导故障排除工作&#xff0c;确定具体的网络问题&#xff0c;实施…

Javascript高级—常见算法

大数相加问题 function sumString(a, b){a a ;b n ;var arrA a.spilt(),arrB b.spilt(),distance arrA.length - arrB.length, // 计算两者的长度差&#xff0c;取最大的那个作为基准点len distance > 0 ? arrA.length : arrB.length,carry 0; // 表示相…

Linux系统常用操作与命令指南

一、快捷分类 1、移动光标 h&#xff0c; j&#xff0c; k&#xff0c; l 左&#xff0c; 下&#xff0c; 上&#xff0c; 右 Ctrl-F:下翻一页 Ctrl-B:上翻一页 Ctrl-U:上翻半页 Ctrl-d:下翻半页 0:跳至行首&#xff0c;不管有无缩进&#xff0c;就是跳到第0个字…

Kafka 与 RabbitMQ 的联系

Kafka 与 RabbitMQ 的区别与联系 一、引言 在现代软件架构中&#xff0c;消息中间件扮演着至关重要的角色。它们帮助系统解耦、提高可伸缩性并确保数据的可靠传递。在众多消息中间件中&#xff0c;Apache Kafka 和 RabbitMQ 是最受欢迎的选择之一。虽然它们都用于消息传递&am…

读取文件内容、修改文件内容、识别文件夹目录(Web操作系统文件/文件夹详解)

前言 因 Unicode IDE 编辑器导入文件、文件夹需要&#xff0c;研究了下导入文件/文件夹的功能实现&#xff0c;发现目前相关文章有点少&#xff0c;故而记录下过程&#xff0c;如果有误&#xff0c;还望指正。(API的兼容性及相关属性、接口定义&#xff0c;请自行查看文件系统 …

SQLite 全文检索:快速高效的文本查询方案

文章目录 什么是全文检索&#xff1f;如何启用 FTS&#xff1f;插入数据执行全文检索关联原始表与 FTS 表数据更新结论 说明: 本文以博客内容全文检索为例。 什么是全文检索&#xff1f; 全文检索是指对文本数据进行索引和查询的一种技术。与常规的 LIKE 查询不同&#xff0c…

【卡尔曼滤波】数据融合Fusion的应用 C语言、Python实现(Kalman Filter)

【卡尔曼滤波】数据融合Fusion的应用 C语言、Python实现&#xff08;Kalman Filter&#xff09; 更新以gitee为准&#xff1a; gitee地址 文章目录 卡尔曼滤波数据融合Python实现C语言实现多个数据如何融合附录&#xff1a;压缩字符串、大小端格式转换压缩字符串浮点数压缩Pac…

docker-hub 无法访问,使用windows魔法拉取docker images再上传到linux docker环境中

云机的服务器是可以docker拉取镜像的&#xff0c;但是本地的虚拟机、物理服务器等网络环境不好的情况&#xff0c;是无法访问docker-hub的&#xff0c;即使更换了docker镜像源国内源也无法使用。 本文章使用 在魔法网络环境下的windows&#xff0c;下载docker images后&#xf…

vxe-vxe-colgroup后端返回数据 对数据进行处理 动态合并分组表头(v-if控制表格渲染(数据请求完成后渲染))

1.html vxe-colgroup循环合并数据&#xff1b;v-if控制表格渲染&#xff08;数据请求完成后渲染&#xff09; <template><vxe-table v-if"isTableReady" :data"tableData"><vxe-colgroup title"基本信息"><template v-for…

Python →爬虫实践

爬取研究中心的书目 现在&#xff0c;想要把如下网站中的书目信息爬取出来。 案例一 耶鲁 Publications | Yale Law School 分析网页&#xff0c;如下图所示&#xff0c;需要爬取的页面&#xff0c;标签信息是“<p>”&#xff0c;所以用 itemssoup.find_all("p&…

【Linux学习】【Ubuntu入门】1-4 ubuntu终端操作与shell命令1

1.使用快捷键CtrlAltT打开命令终端&#xff0c;或者单击右键点击… 2.常用shell命令 目录信息查看命令&#xff1a;ls ls -a&#xff1a;显示目录所有文件及文件夹&#xff0c;包括隐藏文件&#xff0c;比如以.开头的 ls -l&#xff1a;显示文件的详细信息 ls -al&#xff1…

WordPress 6.7 “Rollins”发布

每个 WordPress 版本都会向一位在音乐界留下不可磨灭印记的艺术家致敬。WordPress 6.7 的代号为“Rollins”&#xff0c;旨在向传奇爵士萨克斯演奏家桑尼罗林斯致敬。罗林斯是爵士乐界最伟大的即兴演奏家和先驱之一&#xff0c;他以精湛的技术、创新精神和无畏的音乐表达方式影…

ESXi安装【真机和虚拟机】(超详细)

项目简介&#xff1a; ESXi&#xff08;Elastic Sky X Integrated&#xff09;是VMware公司开发的一种裸机虚拟化管理程序&#xff0c;允许用户在单一物理服务器上运行多个虚拟机&#xff08;VM&#xff09;。它直接安装在服务器硬件上&#xff0c;而不是操作系统之上&#xff…