有时,我们希望类的实例对象有且仅有一个,比如某个页面,我们希望它如果出现,永远只有一个,那么此时你可能就需要用到单例模式了。(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;
}
饿汉式即一种静态初始化的方式,它是类一加载就实例化对象,所以要提前占用系统资源。而懒汉式又面临着多线程不安全的问题,需要加二重锁才能保证安全,因此具体使用哪种模式,需要根据实际需求和场景来定。
以上就是单例模式的实现方式啦,本人也是刚学习总结,如有错误,欢迎指正交流。