单例模式
2021-04-23 本文已影响0人
小幸运Q
- 单例类有一个静态单例类指针,在静态方法中new该指针实例化是懒汉,在单例类外部::初始化该指针是饿汉。
保证一个类仅可以有一个实例化对象,并且提供一个可以访问它的全局接口。实现单例模式必须注意以下几点:
- 单例类只能由一个实例化对象。
- 单例类必须自己提供一个实例化对象。
- 单例类必须提供一个可以访问唯一实例化对象的接口。
单例模式分为懒汉和饿汉两种实现方式。
懒汉模式
不到万不得已就不会去实例化类,也就是说在第一次用到类实例的时候才会去实例化一个对象。在访问量较小,甚至可能不会去访问的情况下,采用懒汉实现,这是以时间换空间。
image.png非线程安全版:
/*
* 关键代码:构造函数是私有的,不能通过赋值运算,拷贝构造等方式实例化对象。
*/
#include<iostream>
using namespace std;
//懒汉式一般实现:非线程安全,getInstance返回的实例指针需要delete
class Singleton
{
public:
static Singleton* getInstance();
~Singleton(){}
private:
Singleton(){} //构造函数私有
Singleton(const Singleton& obj) = delete; //明确拒绝
Singleton& operator=(const Singleton& obj) = delete; //明确拒绝
static Singleton* m_pSingleton;
};
Singleton* Singleton::m_pSingleton = NULL;
// 第一次访问getInstance才会new,并且要在private函数里
Singleton* Singleton::getInstance()
{
if(m_pSingleton == NULL)
{
m_pSingleton = new Singleton;
}
return m_pSingleton;
}
int main(){
// Singleton* s=new Singleton();
// 构造函数私有无法调用
Singleton* s=Singleton::getInstance();
s->print();
}
线程安全版:(双重检查)
也可以先加锁然后检查一次,但是先检查可以避免已分配情况下的加锁操作,减小开销。
std::mutex mt;
class Singleton
{
public:
static Singleton* getInstance();
private:
Singleton(){} //构造函数私有
Singleton(const Singleton&) = delete; //明确拒绝
Singleton& operator=(const Singleton&) = delete; //明确拒绝
static Singleton* m_pSingleton;
};
Singleton* Singleton::m_pSingleton = NULL;
Singleton* Singleton::getInstance()
{
if(m_pSingleton == NULL)
{
mt.lock();
if(m_pSingleton == NULL)
{
m_pSingleton = new Singleton();
}
mt.unlock();
}
return m_pSingleton;
}
饿汉模式
饿了肯定要饥不择食。所以在单例类定义的时候就进行实例化。在访问量比较大,或者可能访问的线程比较多时,采用饿汉实现,可以实现更好的性能。这是以空间换时间。
//饿汉式:线程安全,注意一定要在合适的地方去delete它
class Singleton
{
public:
static Singleton* getInstance();
private:
Singleton(){} //构造函数私有
Singleton(const Singleton&) = delete; //明确拒绝
Singleton& operator=(const Singleton&) = delete; //明确拒绝
static Singleton* m_pSingleton;
};
Singleton* Singleton::m_pSingleton = new Singleton();
Singleton* Singleton::getInstance()
{
return m_pSingleton;
}
最佳方案:
使用静态局部变量
class Single
{
public:
// 获取单实例对象
static Single &GetInstance();
// 打印实例地址
void Print();
private:
// 禁止外部构造
Single();
// 禁止外部析构
~Single();
// 禁止外部复制构造
Single(const Single &signal);
// 禁止外部赋值操作
const Single &operator=(const Single &signal);
};
Single &Single::GetInstance()
{
// 局部静态特性的方式实现单实例
static Single signal;
return signal;
}