c++单例模式

一、什么是单例模式

一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

二、代码结构实现单例模式

单例模式设计思路:在类中声明一个指向自身的静态变量,将构造函数设为私有,给外部提供一个全局函数,唯一能获取这个类的指针的方法。即:外部只能通过一个函数获取相同的一个指针,就是单例模式的核心。
2.1 单例模式简单版(不支持同步)
a.类的声明

class SingleInstance
{
public:
	static SingleInstance*GetInstance();
protected:
	SingleInstance()=default;
	static SingleInstance*mInstance;
};

b.初始化静态变量

SingleInstance* SingleInstance::mInstance = nullptr;

c.实现GetInstance()方法

SingleInstance* SingleInstance::GetInstance()
{
	if (mInstance == nullptr)
		mInstance = new SingleInstance;
	return mInstance;
}

简单版的单例模式,在多线程编程时候不能正常工作,会产生几个或多个实例,是因为线程进入mInstance == nullptr条件的时候,多个线程同时在这个位置,进而new 了多个实例,这个问题在后面的增强版进行优化。
2.1 单例模式增强版(支持同步)
a.类的声明(和简单版一致)
b.初始化静态变量(和简单版一致)
c.添加互斥量对象(用于线程同步,线程同步的方式有很多种,根据自己情况挑选,以后再专门分析各种同步手法)

SingleInstance* SingleInstance::mInstance = nullptr;
std::mutex g_mutex;

d.实现GetInstance()方法,加入同步代码

SingleInstance* SingleInstance::GetInstance()
{
	if (mInstance == nullptr)
	{
		g_mutex.lock();
		if(mInstance==nullptr)
			mInstance = new SingleInstance;
		g_mutex.unlock();
	}
	return mInstance;
}

可以看出,多线程编程时,单例模式依然能正常工作,只有当前获得锁的线程能实例化,并且同时不能让其他线程实例化,系统中始终只有一套实例,这就是单例模式的灵魂。

三、代码实现的注意事项

在编写单例模式时候,由于印象不够深刻,往往会忽略一下细节:
1、默认构造函数,或者自定义构造函数没有私有化,即外部可以直接new,单例模式失效
2、静态变量指针mInstance没有初始化,默认成其他地址,导致始终没有new成功,地址访问报错
3、简单版忘记添加同步锁,导致单例失效

四、单例模式的使用方法

在实际开发过程中,如何切合实际情况使用单例模式,是程序员开发经验和能力的体现。通常一个完善的系统或框架,都会有一份比较完整的数据,这种数据需要确保只有一份,并且公开,每个用户拿到都是相同的一份,一旦修改,所有用户拿到的也为最新的。如多个窗口打开垃圾桶,多个窗口都拿到单一的句柄,如封装好的线程池对象,整个窗口的事例,等等,我们并不少见getInstance这样的一款函数,底层都是单例模式的实现。
假设一个场景,有一款游戏,游戏中有用户的很多信息,如昵称、性别等,在整个游戏过程中,这些信息可能在不同的窗口被获取,或者更改一些数据,这样的数据在系统只保留一份即可,使用单例模式来演示:

class CXGame
{
public:
	static CXGame*GetInstance();
	//各种修改信息、获取信息的成员函数
	...
protected:
	CXGame() = default;
	static CXGame*mInstance;
	string nickname;
	string sex;
	...
};
CXGame* CXGame::GetInstance()
{
	if (mInstance == nullptr)
	{
		g_mutex.lock();
		if (mInstance == nullptr)
			mInstance = new CXGame;
		g_mutex.unlock();
	}
	return mInstance;
}

CXGame* CXGame::mInstance = nullptr;
std::mutex g_mutex;

每当一个新的模块加入新的功能,都可以通过GetInstance()来获取实例,进而修改或获取相关信息。

五、优缺点

1、优点:只有一个实例,节省系统资源,避免频繁创建、销毁;优化和共享资源访问。
2、缺点:不适应频繁变化的对象;没有接口,扩展困难。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值