单例模式
目录
- 目的:主要解决一个全局使用的类频繁的创建和销毁的问题
- 实现:保证一个类只有一个实例存在,同时提供能对该实例加以访问的全局访问方法
- 三要素:(1)构造函数私有化;(2)静态函数,用来获取单例;(3)有一个静态的自身变量成员,用来返回单例对象
- 分类:(1)懒汉式:通过单例函数来获取单例,单例函数中创建对象时,需判断对象是否存在;(2)饿汉式:不通过调用单例函数来获取对象,而是直接在类外部new一个对象,即定义全局变量。
- 注意:懒汉式会出现多线程问题。解决:双重锁机制实现线程安全。
- 使用场景:创建的一个对象需要消耗的资源过多,比如I/O与数据库的连接等。
1、懒汉式
//懒汉式
class LanHanShi
{
public:
static LanHanShi* GetObject()
{
if (lhs == NULL) //判断对象是否已存在,保证只初始化一个对象
{
lhs = new LanHanShi;
/*
若在多线程中,构造函数中有sleep(100);则有多个线程时,在每个线程
创建对象进入这个函数时,会首先判断对象是否已存在,而由于此线程
停留在构造函数中还未返回,所以对象还未创建,另一个线程也将进入构造
函数中,所以此时会创建多个对象,则不再是单例模式。
*/
}
/*解决懒汉式与多线程的问题方法:
if(lhs==NULL) //第一次检查保证所有线程进来之前的判断
{
cs.lock(); //可能到这一步,有好几个线程进来
if(lhs==NULL) //第二次检查,保证在有一个线程已进来创建对象后,
{ //防止其他线程进来再次创建对象
lhs = new LanHanShi;
}
cs.unlock(); //加锁部分为临界区
}
*/
return lhs;
}
~LanHanShi()
{
if (lhs != NULL)
{
delete lhs;
lhs = NULL;
cout << "~LanHanShi()" << endl;
}
}
private:
LanHanShi()
{
cout << "LanHanShi()" << endl;
}
private:
static LanHanShi *lhs;
};
LanHanShi* LanHanShi::lhs = NULL; //静态类型需要在外部定义
//定义格式:(不加static)类型 类名::变量名=初始化值
2、饿汉式
class EHanShi
{
public:
static EHanShi* GetObject() //函数中有静态变量,则函数必须是静态函数
{
return ehs;
}
private:
EHanShi()
{
cout << "EHanShi()" << endl;
}
private:
static EHanShi *ehs;
};
EHanShi* EHanShi::ehs = new EHanShi; //饿汉式直接在类外部进行new对象
//这句话是在调用函数之前就被执行,为全局变量
void EHanShiDisplay()
{
EHanShi *p1 = EHanShi::GetObject();
EHanShi *p2 = EHanShi::GetObject();
}
void LanHanShiDisplay()
{
//懒汉式即只在GetObject执行时才会获取单例
LanHanShi *p1 = LanHanShi::GetObject();
LanHanShi *p2 = LanHanShi::GetObject();
//确实构造函数只执行了一次,创建了一个单例
//单例生命周期和类一样,不会执行析构函数
}
3、测试
int main1()
{
LanHanShiDisplay();
EHanShiDisplay();
//构造函数都只被执行了一次,为单例模式,懒汉式有多线程问题,而饿汉式没有
system("pause");
return 0;
}
结果: