C++设计模式之单例模式详解(懒汉模式、饿汉模式、双重锁)

2020/12/08 12:15
阅读数 316

     有时,我们希望类的实例对象有且仅有一个,比如某个页面,我们希望它如果出现,永远只有一个,那么此时你可能就需要用到单例模式了。(PS:本人亲身经历过手写单例模式的面试,所以以下代码必须能够手撕!!!)

     单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。首先,怎么让类只有一个实例呢?肯定是构造函数需要做点“手脚”了,如果构造函数一如既往的是public属性,那还是可以任意构造对象,则不满足要求了。所以大神们想出来将构造函数私有化的方法,即把构造函数设置成私有属性,并对外提供一个访问的接口。

     单例模式的实现有两种方式:懒汉模式和饿汉模式。懒汉模式:顾名思义,很“懒”,只有用到了才实例化对象并返回(调用了对外的接口才会实例化对象)。饿汉模式:不管调不调用对外接口,都已经实例化对象了。下面先实现基本的懒汉模式,代码如下:

#include<iostream>

using namespace std;
/*单例模式:构造函数私有化,对外提供一个接口*/

//线程不安全的懒汉模式
class singleClass {
public:
	static singleClass* instance;//静态成员变量,类内声明,类外初始化
	static singleClass* getinstance()//对外的接口(方法),静态成员函数调用静态成员变量
	{
		if (instance == nullptr)
		{
			instance = new singleClass();
		}
		return instance;
	};

private:
	singleClass() {};//构造函数属性设置为私有
};
singleClass* singleClass::instance=nullptr;//初始化静态变量

int main()
{
    //懒汉模式
	singleClass* singlep1=singleClass::getinstance();//通过类域获取接口
	singleClass* singlep2 = singleClass::getinstance();

    cout << singlep1 << endl;
	cout << singlep2 << endl;

    system("pause");
	return 0;
}

由于没有了对象,所以将instance设置为static属性,让其能通过类名来访问获取。但是在多线程环境下,这种实现方式是不安全的,原因在于在判断instance是否为空时,可能存在多个线程同时进入if中,此时可能会实例化多个对象。于是,我了解决这个问题,出现了二重锁的懒汉模式,实现代码如下:

#include<iostream>
#include<mutex>

using namespace std;
/*单例模式:构造函数私有化,对外提供一个接口*/

//线程安全的单例模式
class lhsingleClass {
public:
	static lhsingleClass* instance;
	static mutex i_mutex;//锁
	static lhsingleClass* getinstance()
	{//双重锁模式
		if (instance == nullptr)
		{//先判断是否为空,如果为空则进入,不为空说明已经存在实例,直接返回
            //进入后加锁
			i_mutex.lock();
			if (instance == nullptr)
			{//再判断一次,确保不会因为加锁期间多个线程同时进入
				instance = new lhsingleClass();
			}
			i_mutex.unlock();//解锁
		}
		return instance;
	}
private:
	lhsingleClass(){}
};
lhsingleClass* lhsingleClass::instance=nullptr;
mutex lhsingleClass::i_mutex;//类外初始化


int main()
{
	lhsingleClass* lhsinglep5 = lhsingleClass::getinstance();
	lhsingleClass* lhsinglep6 = lhsingleClass::getinstance();

	cout << lhsinglep5 << endl;
	cout << lhsinglep6 << endl;
	system("pause");
	return 0;
}

以上就是单例模式的懒汉实现方式,下面介绍饿汉实现方式:

#include<iostream>

using namespace std;
/*单例模式:构造函数私有化,对外提供一个接口*/

//饿汉模式:不管用不用得到,都构造出来。本身就是线程安全的
class ehsingleClass {
public:
	static ehsingleClass* instance;//静态成员变量必须类外初始化,只有一个
	static ehsingleClass* getinstance()
	{
		return instance;
	}

private:
	ehsingleClass() {}
};
ehsingleClass* ehsingleClass::instance = new ehsingleClass();
//类外定义,main开始执行前,该对象就存在了

int main()
{
	//饿汉模式
	ehsingleClass* ehsinglep3 = ehsingleClass::getinstance();
	ehsingleClass* ehsinglep4 = ehsingleClass::getinstance();
	//ehsingleClass* ehsinglep5 = ehsingleClass::get();//非静态成员方法必须通过对象调用,不能通过类域访问

	cout << ehsinglep3 << endl;
	cout << ehsinglep4 << endl;

	system("pause");
	return 0;
}

    饿汉式即一种静态初始化的方式,它是类一加载就实例化对象,所以要提前占用系统资源。而懒汉式又面临着多线程不安全的问题,需要加二重锁才能保证安全,因此具体使用哪种模式,需要根据实际需求和场景来定。

    以上就是单例模式的实现方式啦,本人也是刚学习总结,如有错误,欢迎指正交流。

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部