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

C++练级计划->《单例模式》懒汉和饿汉

目录

单例模式是什么?

单例模式的应用:

饿汉单例模式:

1.实现:

 2.理解:

懒汉单例模式:

1.实现:

2.理解:

懒汉和饿汉的优缺点

饿汉模式的优点:

饿汉模式的缺点:

懒汉模式的优点:

懒汉模式的缺点:


单例模式是什么?

单例模式顾名思义:单个实例,就是说一个类只能实例化出一个对象。通常都是作为全局对象,要让所有人都能访问,但是只有一份。

单例模式的应用:

日志记录:通常在开发过程中是多人的,那就会有很多人来写日志。这时候就需要一个日志记录器,用于记录所有模块的日志信息,所以这个记录器应该是针对所有人的,并且为了避免重复,所以使用单例模式

相似的还有配置管理,连接池管理,全局状态管理

在多线程下的线程安全对象。有些对象需要确保只有一个实例被多个线程共享(多个线程使用一个对象)。结合锁的使用,可以保证这个单独对象在多线程下的安全性和一致性。

饿汉单例模式:

1.实现:

单例模式的使用方式就是:这个对象初始化完后,只能通过一个静态接口获取,并且要把构造函数和赋值构造拷贝构造都放入私有中。如下代码:

class Singleton{public:static Singleton* GetInstance() //通过调用GetInstance() 在类外获得实例{	return &_slt;                //返回这个实例的地址}void print()                   //输出实例的数据{cout << _x << " " << _y << endl;for (auto e : _vect){cout << e << " ";}cout << endl;}void Add_Vect(int n)         //对实例的Vector进行尾插{_vect.push_back(n);}private:int _x;int _y;vector<int>_vect;static Singleton _slt; //类内声明//因为要实现单例类(全局只能有一个对象,因此要将构造函数私有化否则可以在类外随便创建)Singleton(int x = 1, int y = 1, const vector<int>& v = { 1,2,3,4,5 }):_x(x), _y(y), _vect(v){}//禁用拷贝构造和赋值重载Singleton(const Singleton& hs) = delete;Singleton& operator=(const Singleton& hs) = delete;};//类外初始化Singleton Singleton::_slt(2, 2,{ 4,5,6 });//测试懒汉void Test01(){//Singleton::GetInstance()返回创建静态对象的指针Singleton::GetInstance()->print();Singleton::GetInstance()->print();cout << "对象1的地址为:" << Singleton::GetInstance() << endl;cout << "对象2的地址为:" << Singleton::GetInstance() << endl;//结果为://2 2 //4 5 6//后面两个地址是一样的(也就是返回的都是同一个实例)}

 2.理解:

1.饿汉模式解释:

顾名思义:饿汉,就是一个很饿的人,只要有东西吃立马就吃了,没有任何等待的所以饿汉模式就是在还没进入main函数前就实例好的模式。

2.为什么要把三种构造函数私有化?

很显然我们要实现单例,那就不允许你在类外调用构造函数,生成这个对象,所以我们在类内就声明了这个对象,初始化时也是只能对这个对象(_slt)初始化。拷贝和赋值也是同理,我只能有一个这个对象,所以不允许你拷贝和赋值

3.然后实现的饿汉模式(对上面代码的解释)

static Singleton _slt; //类内声明

我们在类内声明了这个对象,然后把三个构造函数给私有化,所以现在就只剩下这一个对象

又因为单例模式是全局给所有人使用的所以在类外初始化时是全局初始化

//类外初始化Singleton Singleton::_slt(2, 2,{ 4,5,6 });

接下来要调用这个对象,只能通过先指定要调用的类然后GetInstance()找到这个单例对象。然后才能调用对应的接口。因为无法构造,且调用时只能通过接口,所以不用担心对象被修改。所以实现了单例模式

static Singleton* GetInstance() //通过调用GetInstance() 在类外获得实例{    return &_slt;                //返回这个实例的地址}
//Singleton::GetInstance()返回创建静态对象的指针Singleton::GetInstance()->print();Singleton::GetInstance()->print();

懒汉单例模式:

顾名思义:懒汉,就是很懒的一个人,顶级拖延症,只有必要时才会做对应的事,所以懒汉就是只有要使用这个实例时才进行创建

1.实现:

class Singleton{public:static Singleton* GetInstance() //必须定义为静态函数因为只有这样才可以不创建对象去调用它来创建对象{								//否则所有成员函数要通过对象去调用(若不设置为静态的无法创建出来对象(构造函数私有了))static Singleton slt(2, 2, {7,8,9});		//静态函数每次只会初始化一次 所以只会在第一次调用时初始化return &slt;                //下次调用GetInstance()会直接返回&slt}void print(){cout << _x << " " << _y << endl;for (auto e : _vect){cout << e << " ";}cout << endl;}void Add_Vect(int n){_vect.push_back(n);}private:int _x;int _y;vector<int>_vect;//因为要实现单例类(全局只能有一个对象,因此要将构造函数私有化否则可以在类外随便创建)Singleton(int x = 1, int y = 1, const vector<int>& v = { 1,2,3,4,5 }):_x(x), _y(y), _vect(v){}//禁用拷贝构造和赋值重载Singleton(const Singleton& hs) = delete;Singleton& operator=(const Singleton& hs) = delete;};//测试懒汉void Test01(){//Singleton::GetInstance()返回创建静态对象的指针Singleton::GetInstance()->print();    Singleton::GetInstance()->print();cout << "对象1的地址为:" << Singleton::GetInstance() << endl;cout << "对象2的地址为:" << Singleton::GetInstance() << endl;//结果为:(因为调用两次所以打印两次)//2 2 //7 8 9//2 2//7 8 9//后面两个地址是一样的}

2.理解:

1.创建时机:

这里我们和饿汉不同的点就是我们把slt的初始化放到了GetInstance()里,所以只有有人调用时才会创建这个slt。

2.slt会不会重复创建:

当然不会,这里就要先理解一下静态成员:静态成员在一个对象中只会初始化一次并存入静态区中。所以不会重复创建。当然三个构造函数还是要私有化,不能让别人使用构造。

懒汉和饿汉的优缺点


饿汉模式的优点:

  • 线程安全:在类加载的时候就创建实例,不存在多线程环境下的线程安全问题(还没进入主函数就创建完实例了,所以不用担心线程安全问题)。

饿汉模式的缺点:

  • 可能会造成资源浪费:在程序运行过程中始终存在实例,可能会占用一定的资源。
  • 不支持延迟加载:无法实现延迟加载的特性。就是说如果这个单例很大,那在开始时,可能会一直卡着,直到这个单例初始化完成。

懒汉模式的优点:

  • 延迟加载:在第一次调用时才创建实例,节省资源。
  • 节约内存:只有在需要时才创建实例,避免资源浪费。

懒汉模式的缺点:

  • 线程安全性问题:在多线程环境下,需要额外的同步措施来保证线程安全。
  • 可能存在性能问题:在第一次调用时需要进行实例化,可能会影响程序性能。
http://www.lryc.cn/news/491854.html

相关文章:

  • SQL for XML
  • 如何使用GCC手动编译stm32程序
  • 在线绘制Nature Communication同款双色、四色火山图,突出感兴趣的基因
  • C语言:C语言实现对MySQL数据库表增删改查功能
  • C++ 二叉搜索树(Binary Search Tree, BST)深度解析与全面指南:从基础概念到高级应用、算法优化及实战案例
  • 刷题日常(移动零,盛最多水的容器,三数之和,无重复字符的最长子串)
  • 深入了解决策树---机器学习中的经典算法
  • Elasticsearch对于大数据量(上亿量级)的聚合如何实现?
  • 深度学习模型:循环神经网络(RNN)
  • 前端---HTML(一)
  • SQL 复杂查询
  • 银河麒麟桌面系统——桌面鼠标变成x,窗口无关闭按钮的解决办法
  • 抓包之使用chrome的network面板
  • 避坑ffmpeg直接获取视频fps不准确
  • 大数据新视界 -- 大数据大厂之 Hive 函数库:丰富函数助力数据处理(上)(11/ 30)
  • 深入解析 Django 中数据删除的最佳实践:以动态管理镜像版本为例
  • 【java】sdkman-java多环境切换工具
  • 11.25c++继承、多态
  • STM32F103外部中断配置
  • 阿里电商大整合,驶向价值竞争新航道
  • 等保测评在云计算方面的应用讲解
  • QML TableView 实例演示 + 可能遇到的一些问题(Qt_6_5_3)
  • SpringBoot(三十九)SpringBoot集成RabbitMQ实现流量削峰添谷
  • 前端 Vue 3 后端 Node.js 和Express 结合cursor常见提示词结构
  • 类和对象(下):点亮编程星河的类与对象进阶之光
  • 42.接雨水
  • 使用Java代码操作Kafka(五):Kafka消费 offset API,包含指定 Offset 消费以及指定时间消费
  • Ubuntu安装不同版本的opencv,并任意切换使用
  • 突破内存限制:Mac Mini M2 服务器化实践指南
  • 【排版教程】Word、WPS 分节符(奇数页等) 自动变成 分节符(下一页) 解决办法