一、什么是单例模式模式?
单例模式是常用的基础设计模式,单例模式指在整个系统生命周期里,保证一个类只能产生一个实例,确保该类的唯一性。
单例模式分类
单例模式可以分为懒汉式和饿汉式,两者之间的区别在于创建实例的时间不同:
懒汉式:程序开始运行时单例并不存在,只有当需要使用该实例时,才会去创建并使用实例。(这种方式要考虑线程安全)
饿汉式:程序开始运行时就初始化创建实例,当需要时,直接调用即可。(本身就线程安全,没有多线程的问题)
单例类特点
- 构造函数和析构函数为private类型,目的禁止外部构造和析构
- 拷贝构造和赋值构造函数为private类型,目的是禁止外部拷贝和赋值,确保实例的唯一性
- 类里有个获取实例的静态函数,可以全局访问
二、懒汉模式(单线程,线程不安全)
简单的单例模式实现,可以在单线程下使用,多线程模式下会造成线程不安全。
#include <iostream>
using namespace std;
class Singleton
{
public:
//获取单例对象
static Singleton * GetInstance();
//释放单例对象
static void DeleteInstance();
private:
//把构造函数、拷贝构造函数、赋值构造函数私有化,这样在类外就只能通过我们给出的接口函数获取实例了
Singleton();
~Singleton();
Singleton(const Singleton &);
Singleton & operator=(const Singleton &);
// 唯一单例对象指针
static Singleton * p;
};
//类外初始化静态成员变量
Singleton * Singleton::p=nullptr;
Singleton::Singleton()
{
}
Singleton::~Singleton()
{
}
Singleton * Singleton::GetInstance()
{
if(p==nullptr)
{
p=new Singleton();
}
return p;
}
void Singleton::DeleteInstance()
{
if(p)
{
delete p;
p=nullptr;
}
}
三、懒汉模式(加锁,线程安全)
#include <iostream>
#include<pthread.h>
using namespace std;
class Singleton
{
public:
//获取单例对象
static Singleton * GetInstance();
//释放单例对象
static void DeleteInstance();
private:
//把构造函数、拷贝构造函数、赋值构造函数私有化,这样在类外就只能通过我们给出的接口函数获取实例了
Singleton();
~Singleton();
Singleton(const Singleton &);
Singleton & operator=(const Singleton &);
// 唯一单例对象指针
static Singleton * p;
static pthread_mutex_t lock;
};
//类外初始化静态成员变量
Singleton * Singleton::p=nullptr;
pthread_mutex_t Singleton::lock=PTHREAD_MUTEX_INITIALIZER;
Singleton::Singleton()
{
}
Singleton::~Singleton()
{
}
Singleton * Singleton::GetInstance()
{
//最外层的if(p==nullptr),目的是为了尽量避免加锁,毕竟加锁的开销有点大
if(p==nullptr)
{
pthread_mutex_lock(&lock);
if(p==nullptr)
{
p=new Singleton();
}
pthread_mutex_unlock(&lock);
}
return p;
}
void Singleton::DeleteInstance()
{
pthread_mutex_lock(&lock);
if(p)
{
delete p;
p=nullptr;
}
pthread_mutex_unlock(&lock);
}
四、懒汉模式(线程安全,静态局部变量特性)
c++11特性,static修饰局部变量时,局部变量将会在全局数据区分配内存,直到程序运行结束才会释放内存,并且可以通过引用或指针在函数外部使用该局部变量。静态局部变量只初始化一次(实测是在第一次调用时初始化),之后每次调用函数时不再重新赋值,具有线程安全特性。在定义静态局部变量时不赋值的话,会执行默认初始化。
#include<iostream>
using namespace std;
class Singleton
{
public:
static Singleton & GetInstance();
private:
//把构造函数、拷贝构造函数、赋值构造函数私有化,这样在类外就只能通过我们给出的接口函数获取实例了
Singleton();
~Singleton();
Singleton(const Singleton &);
Singleton & operator=(const Singleton &);
};
Singleton::Singleton()
{
}
Singleton::~Singleton()
{
}
Singleton & Singleton::GetInstance()
{
// 局部静态特性的方式实现单实例
static Singleton single;
return single;
}
五、饿汉模式
#include <iostream>
using namespace std;
class Singleton
{
public:
//获取单例对象
static Singleton * GetInstance();
private:
//把构造函数、拷贝构造函数、赋值构造函数私有化,这样在类外就只能通过我们给出的接口函数获取实例了
Singleton();
~Singleton();
Singleton(const Singleton &);
Singleton & operator=(const Singleton &);
// 唯一单例对象指针
static Singleton * p;
};
//类外初始化静态成员变量
Singleton * Singleton::p=new Singleton();
Singleton::Singleton()
{
}
Singleton::~Singleton()
{
}
Singleton * Singleton::GetInstance()
{
return p;
}