单例模式:饿汉式与懒汉式

单例模式

在介绍单例模式前,我们先来理解一下设计模式的概念以及使用设计模式的目的:

  • 设计模式:就是一套被反复利用、众人知晓、经过分类的、代码设计经验的总结。
  • 使用其目的:就是为了代码的可重用性、让代码更容易被他人理解、保证代码可靠性。

作为设计模式的一种,单例模式自然也具有以上特点,那么现在我们就来说一下单例模式的概念及作用:

  • 单例模式:即一个类只能创建一个对象,
  • 作用:保证系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。
    我们可以这样来理解:假设在一个服务器程序中,服务器的配置信息存放在一个文件中,由一个单例对象来统一读取这些配置数据,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息,这样子就可以简化在复杂环境下的配置管理。

单例模式有两种实现方式:

1.饿汉模式

通俗一点来说,饿汉模式就是:不管以后用不用,程序在启动时就创建一个唯一的实例对象。

class Singleton
{
public:
	static Singleton* GetInstance()
	{
		return &m_instance;
	}

private:
	// 构造函数私有
	Singleton()
	{}

	// C++98防拷贝
	Singleton(const Singleton&);
	Singleton& operator=(const Singleton&);

	// C++11防拷贝
	Singleton(const Singleton&) = delete;
	Singleton& operator=(const Singleton&) = delete;

	static Singleton m_instance;
};

Singleton Singleton::m_instance;	// 在程序入口之前就完成单例对象的初始化

由此我们可以看到饿汉模式的优缺点:

  • 优点:
    1.实现简单
    2.如果这个单例对象在多线程高并发环境下频繁使用,性能要求较高,那么明显使用饿汉模式来避免资源竞争,提高响应速度效果更好;
  • 缺点:
    1.可能会导致进程启动慢,
    2.如果有多个单例,类对象实例启动顺序不确定。
2.懒汉模式

了解了上面的饿汉模式,知道了其缺点,再看懒汉、饿汉模式两者的名字,我们便可以对其略知一二。
如果单例对象构造非常耗时或者占用很多资源,如:加载插件、初始化网络连接、读取文件等,而可能该对象在程序运行时并不会用到,那么也要在程序一开始就进行初始化,就会导致程序启动时非常的缓慢。因此这种情况下使用懒汉模式(延迟加载)的效果更好。

#include <iostream>
#include <mutex>
#include <thread>

class Singleton
{
public:
	static Singleton* GetInstance()
	{
		// 注意这里一定要使用 Double-Check 的方式加锁,才能保证效率和线程安全
		if (nullptr == m_pInstance)
		{
			m_mtx.lock();
			if (nullptr == m_pInstance)
			{
				m_pInstance = new Singleton;
			}
			m_mtx.unlock();
		}
		return m_pInstance;
	}

	// 实现一个内嵌的垃圾回收类
	class CGarbo
	{
	public:
		~CGarbo()
		{
			if (Singleton::m_pInstance)
				delete Singleton::m_pInstance;
		}
	};

	// 定义一个静态的成员变量,程序结束时,系统会自动调用它的析构函数从而释放单例对象
	static CGarbo Garbo;

private:
	// 构造函数私有
	Singleton()
	{}

	// 防拷贝
	Singleton(const Singleton&);
	Singleton& operator=(const Singleton&);

	static Singleton* m_pInstance;	// 单例对象指针
	static mutex m_mtx;	// 互斥锁
};

Singleton* Singleton::m_pInstance = nullptr;
Singleton::CGarbo Garbo;
mutex Singleton::m_mtx;

void Func(int n)
{
	cout << Singleton::GetInstance() << endl;
}

// 多线程环境下演示上面 GetInstance() 加锁和不加锁的区别
int main()
{
	thread t1(Func, 10);
	thread t2(Func, 10);

	t1.join();
	t2.join();

	cout << Singleton::GetInstance() << endl;
	cout << Singleton::GetInstance() << endl;

	return 0;
}

由此我们可以看到懒汉模式的优缺点:

  • 优点:
    1.在第一次使用实例对象时,创建对象,进程启动无负载,
    2.多个单例实例启动顺序自由控制。
  • 缺点:
    1.实现复杂。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值