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

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.kler.cn/a/412984.html

相关文章:

  • 使用PHP实现用户权限控制系统
  • c++的虚继承说明、案例、代码
  • 网络药理学之薛定谔Schrödinge Maestro:6、分子对接(Glide、Ligand docking)和可视化
  • 【人工智能】Python常用库-TensorFlow常用方法教程
  • C语言编译和链接讲解
  • 【k8s深入学习之 Scheme】全面理解 Scheme 的注册机制、内外部版本、自动转换函数、默认填充函数、Options等机制
  • RocketMQ: 消息过滤,通信组件,服务发现
  • 探索Python WebSocket新境界:picows库揭秘
  • 哈希表理解与底层模拟实现
  • Python的排序算法
  • 深度学习创新点不足?试试贝叶斯神经网络!
  • Python中的DrissionPage详解
  • Rust eyre 错误处理实战教程
  • 针对静态交通停车诱导系统解决方案及停车开源框架实现
  • 目录遍历漏洞-CVE-2021-41773
  • C#基础31-35
  • 极狐GitLab 17.6 正式发布几十项与 DevSecOps 相关的功能【一】
  • 『VUE』elementUI dialog的子组件created生命周期不刷新(详细图文注释)
  • 【go】查询某个依赖是否存在于这个代理
  • 【Python TensorFlow】进阶指南(续篇四)