单例模式(Singleton)
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
代码:https://github.com/duyilong/Design-pattern/tree/master/Singleton
- 保证仅有一个实例:不允许随意new,将构造函数、复制构造函数、赋值运算符声明为私有private,注意,析构函数也要声明为私有。
- 全局访问点:静态的GetInstance方法、静态的DeleteInstance方法。
根据instance创建的时间分为饿汉式和懒汉式两种实现方式。
饿汉式:the Singleton instance is EARLY createed at compile time。
懒汉式:the Singleton instance is LAZILY created at runtime。
先看代码,
1. 线程安全单例类的懒汉式实现
#include <mutex> //std::mutex
class Singleton_lazy
{
public:
static Singleton_lazy *&GetInstance() ; //注意返回值类型,对一个指针变量的引用
static void DeleteInstance();
private:
Singleton_lazy() {}
~Singleton_lazy() {}
Singleton_lazy(const Singleton_lazy &singleton) {}
const Singleton_lazy operator=(const Singleton_lazy &singleton) {}
private:
static Singleton_lazy *m_instance;
static std::mutex m_mutex;
};
// 初始化静态成员变量
Singleton_lazy *Singleton_lazy::m_instance = NULL;
std::mutex Singleton_lazy::m_mutex;
// 成员函数实现
Singleton_lazy *&Singleton_lazy::GetInstance()
{
if (m_instance == NULL) //双重锁定,防止每次调用GetInstance都要加锁,只有发现需要实例化的时候才加锁
{
//如果两个线程同时通过了第一重的m_instance==NULL判断,就会有一个先加锁然后创建出来m_instance。
//所以还需要第二重判断m_instance==NULL,防止被实例化出多个对象
std::unique_lock<std::mutex> lock(m_mutex); //加锁
if (m_instance == NULL) //
{
m_instance = new Singleton_lazy;
}
}
return m_instance;
}
void Singleton_lazy::DeleteInstance()
{
std::unique_lock<std::mutex> lock(m_mutex);
if (m_instance)
{
delete m_instance;
m_instance = NULL;
}
}
注意:
- GetInstance方法的返回类型。对一个指针变量的引用,可行;指向引用的指针,不对。
- GetInstance方法的双重锁定。
- 在类的声明体外对static成员变量进行定义和初始化。(注意:对于一般的类,可以只在类体外对static成员定义,然后在构造函数中初始化。注意区分声明、定义和初始化的区别。声明 [声明语句为类体内的static std::mutex m_mutex] 不会给变量分配内存空间,定义 [定义语句为类体外的std::mutex Singleton_lazy::mutex; 对instance变量的定义和初始化在同一个语句中] 才会给变量分配内存空间。)
2.C++11线程安全单例类的懒汉式实现
class Single
{
public:
// 获取单实例对象
static Single &GetInstance()
{
// c++11内部静态变量具有线程安全性,所以可以利用这个特性很简单就实现一个线程安全的单例类
// 局部静态特性的方式实现单实例
static Single instance;
return instance;
}
private:
Single(); // 禁止外部构造
~Single(); // 禁止外部析构
Single(const Single &signal); // 禁止外部复制构造
const Single &operator=(const Single &signal); // 禁止外部赋值操作
};
3.单例类的饿汉式实现(天生线程安全)
饿汉式利用语言运行时库的“静态初始化”特性,在单例类的实现代码一加载到程序中的时候,就在内存中实例化出了一个单例类的实例。
// 单例类饿汉式实现
// 本身具有线程安全性
#include <iostream>
using namespace std;
namespace myspace
{
class singleton_early
{
public:
static singleton_early *GetInstance()
{
return g_psingle;
}
static void DeleteInstance()
{
if (g_psingle)
{
delete g_psingle;
g_psingle = NULL;
}
}
void test()
{
printf("test early singleton\n");
}
private:
singleton_early() {}
~singleton_early() {}
singleton_early(const singleton_early &single) {}
const singleton_early &operator=(const singleton_early &single) {}
private:
static singleton_early *g_psingle;
};
// 静态成员变量的初始化
singleton_early *singleton_early::g_psingle = new singleton_early;
} // namespace myspace