论坛
潜水/灌水快乐,沉淀知识,认识更多同行。
ToB圈子
加入IT圈,遇到更多同好之人。
朋友圈
看朋友圈动态,了解ToB世界。
ToB门户
了解全球最新的ToB事件
博客
Blog
排行榜
Ranklist
文库
业界最专业的IT文库,上传资料也可以赚钱
下载
分享
Share
导读
Guide
相册
Album
记录
Doing
搜索
本版
文章
帖子
ToB圈子
用户
免费入驻
产品入驻
解决方案入驻
公司入驻
案例入驻
登录
·
注册
只需一步,快速开始
账号登录
立即注册
找回密码
用户名
Email
自动登录
找回密码
密码
登录
立即注册
首页
找靠谱产品
找解决方案
找靠谱公司
找案例
找对的人
专家智库
悬赏任务
圈子
SAAS
IT评测·应用市场-qidao123.com
»
论坛
›
物联网
›
物联网
›
C++设计模式--单例模式
C++设计模式--单例模式
南飓风
论坛元老
|
2024-8-5 04:19:56
|
显示全部楼层
|
阅读模式
楼主
主题
1027
|
帖子
1027
|
积分
3081
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要
登录
才可以下载或查看,没有账号?
立即注册
x
参考C++设计模式 - 单例模式_单例模式大秦坑王-CSDN博客
单例模式简介
单例模式指的是,无论怎么获取,
永远只能得到该类类型的唯逐一个实例对象
,那么设计一个单例就必须要满足下面三个条件:
构造函数私有化,这样用户就不能任意定义该类型的对象了
定义该类型唯一的对象
通过一个static静态成员方法返回唯一的对象实例
饿汉单例模式
饿汉式
单例模式,顾名思义,就是
步伐启动时就实例化了该对象
,并没有推迟到第一次使用该对象时再进行实例化;如果运行过程中没有使用到,该实例对象就被浪费掉了。
class CSingleton{
public:
static CSingleton* getInstance()
{
return &single;
}
private:
static CSingleton single;
CSingleton() { cout << "CSingleton()" << endl; }
~CSingleton() { cout << "~CSingleton()" << endl; }
CSingleton(const CSingleton&);
// 防止外部使用拷贝构造产生新的对象,如下面CSingleton s = *p1;
};
CSingleton CSingleton::single;
int main(){
CSingleton *p1 = CSingleton::getInstance();
CSingleton *p2 = CSingleton::getInstance();
CSingleton *p3 = CSingleton::getInstance();
cout<<p1<<" "<<p2<<" "<<p3<<endl;
return 0;
}
复制代码
是否线程安全?
饿汉单例模式中,单例对象定义成了一个static静态对象,它是在步伐启动时,main函数运行之前就初始化好的,因此
不存在线程安全问题,可以放心的在多线程环境中使用
。
懒汉单例模式
步伐启动时,只对single指针初始化了空值,等第一次调用getInstance函数时,由于single指针为nullptr,才进行对象的实例化,所以是一个
懒汉式
单例模式(对象的实例化,耽误到第一次使用它的时候)。
class CSingleton{
public:
static CSingleton* getInstance(){
if (nullptr == single){
single = new CSingleton();
}
return single;
}
private:
static CSingleton *single;
CSingleton() { cout << "CSingleton()" << endl; }
~CSingleton() { cout << "~CSingleton()" << endl; }
CSingleton(const CSingleton&);
};
CSingleton* CSingleton::single = nullptr;
int main(){
CSingleton *p1 = CSingleton::getInstance();
CSingleton *p2 = CSingleton::getInstance();
CSingleton *p3 = CSingleton::getInstance();
cout << p1 << " " << p2 << " " << p3 << endl;
return 0;
}
复制代码
上面new出来的对象,没见过delete,这样不好吧,固然了,有new没有delete,不配对啊!尚有人说,管它呢,当进步程结束的时候,体系反正会回收分配给它的全部资源,包括未回收的内存,但是作为C++开发者,资源的分配和回收,我们必须要考虑清晰,不能糊涂,那么下面的修改感觉如何:
int main(){
CSingleton *p1 = CSingleton::getInstance();
CSingleton *p2 = CSingleton::getInstance();
CSingleton *p3 = CSingleton::getInstance();
cout << p1 << " " << p2 << " " << p3 << endl;
delete p1; // 这里delete之前new过的对象,析构对象并且释放堆上的内存
return 0;
}
复制代码
这种方式怎么看,怎么不舒服,起首资源的开释如果交给用户来操作,难免会忘记写delete,又大概多次delete,成开释野指针了,所以上面开释单例对象资源的方式不够好,我们利用static静态对象在步伐结束时自动析构这么一个特征,给出如下开释资源的代码,肯定比上面的方式要好,代码如下:
class CSingleton{
public:
static CSingleton* getInstance(){
if (nullptr == single){
single = new CSingleton();
}
return single;
}
private:
static CSingleton *single;
CSingleton() { cout << "CSingleton()" << endl; }
~CSingleton() { cout << "~CSingleton()" << endl; }
CSingleton(const CSingleton&);
// 定义一个嵌套类,在该类的析构函数中,自动释放外层类的资源
class CRelease{
public:
~CRelease() { delete single; }
};
// 通过该静态对象在程序结束时自动析构的特点,来释放外层类的对象资源
static CRelease release;
};
CSingleton* CSingleton::single = nullptr;
CSingleton::CRelease CSingleton::release;
int main(){
CSingleton *p1 = CSingleton::getInstance();
CSingleton *p2 = CSingleton::getInstance();
CSingleton *p3 = CSingleton::getInstance();
cout << p1 << " " << p2 << " " << p3 << endl;
return 0;
}
复制代码
是否线程安全?
1.
static CSingleton* getInstance(){
if (nullptr == single){
single = new CSingleton();
}
return single;
}
复制代码
很显着,这个getInstance是个不可重入函数,也就它在多线程环境中执行,会出现
竞态条件
问题,起首搞清晰这句代码,single = new CSingleton()它会做三件事变,
开发内存,调用构造函数,给single指针赋值
,那么在多线程环境下,就有大概出现如下问题:
线程A先调用getInstance函数,由于single为nullptr,进入if语句
new操作先开发内存,此时A线程的CPU时间片到了,切换到B线程
B线程由于single为nullptr,也进入if语句了,开始new操作
很显着,上面两个线程都进入了if语句,都试图new一个新的对象,不符合单例模式的设计,那该如何处理呢?对了,应该为getInstance函数内部加锁,在线程间进行互斥操作。此处使用
锁+双重判断
,也叫
双重查验锁
,代码如下:
static CSingleton* getInstance(){
if (nullptr == single){
// 获取互斥锁
pthread_mutex_lock(&mutex);
// 这里需要再添加一个if判断,否则当两个线程都进入这里,又会多次new对象
if(nullptr == single){
single = new CSingleton();
}
// 释放互斥锁
pthread_mutex_unlock(&mutex);
}
return single;
}
复制代码
2.
#include <iostream>
using namespace std;
class CSingleton{
public:
static CSingleton* getInstance(){
static CSingleton single; // 懒汉式单例模式,定义唯一的对象实例
return &single;
}
private:
static CSingleton *single;
CSingleton() { cout << "CSingleton()" << endl; }
~CSingleton() { cout << "~CSingleton()" << endl;}
CSingleton(const CSingleton&);
};
int main(){
CSingleton *p1 = CSingleton::getInstance();
CSingleton *p2 = CSingleton::getInstance();
CSingleton *p3 = CSingleton::getInstance();
return 0;
}
复制代码
对于static静态局部变量的初始化,编译器会自动对它的初始化进行加锁息争锁控制,使静态局部变量的初始化成为线程安全的操作,不用担心多个线程都会初始化静态局部变量,因此上面的懒汉单例模式是线程安全的单例模式!
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复
使用道具
举报
0 个回复
倒序浏览
返回列表
快速回复
高级模式
B
Color
Image
Link
Quote
Code
Smilies
您需要登录后才可以回帖
登录
or
立即注册
本版积分规则
发表回复
回帖并转播
回帖后跳转到最后一页
发新帖
回复
南飓风
论坛元老
这个人很懒什么都没写!
楼主热帖
零信任介绍
容斥原理
开源SPL助力JAVA处理公共数据文件(txt ...
使用 Helm 安装 MQTT 服务器-EMQX ...
数理逻辑第1-3章
Ubuntu如何安装Mysql+启用远程连接[完 ...
dotnet 修复在 Linux 上使用 SkiaSharp ...
DOS窗口命令和单表简单查询
Java笔记(13) 简单的Lambda表达式 ...
.gitignore文件配置以及gitee提交报Pus ...
标签云
AI
运维
CIO
存储
服务器
浏览过的版块
鸿蒙
程序人生
DevOps与敏捷开发
分布式数据库
Java
前端开发
IOS
网络安全
移动端开发
快速回复
返回顶部
返回列表