目录
概述
懒汉式:
优点:
缺点:
实例:
饿汉式:
优点:
缺点:
实例:
局部静态变量方法:
线程安全模式:
#1 静态成员指针成员:
#2 静态成员指针成员(改进型):
#3 静态成员对象
#4 静态局部对象
#5 静态成员指针成员(动态释放)
单例模式是一个创建型设计模式,一个类只会创建一个对象。
由于只有一个对象,所以不能够通过new来创建对象,因此类的构造函数得是private的
由于不能够new出对象,所以类内部需要提供一个函数来获取对象,这个函数和对象都是属于类的,而不是对象,因此这个函数和唯一 的对象都得是static的,并且对象是private类型的,函数是public类型的
创建单例的基本步骤:
1. 构造函数私有化,避免外部使用构造函数来创建对象
2. 增加静态私有的当前类的指针变量
3. 提供静态的public接口,可以让用户获取单例
使用场景:
一个类只需要一个对象实例
UML图
第一次调用的时候才初始化,避免内存浪费
必须加锁才能够保证单例,加锁会影响效率
class SingletonLazy{
private:
SingletonLazy(){
std::cout << "single lazy!" << std::endl;
}
public:
static SingletonLazy* getInstatce(){
if( NULL == lazy ){
lazy = new SingletonLazy;
}
return lazy;
}
private:
static SingletonLazy* lazy;
};
//类外初始化
SingletonLazy* SingletonLazy::lazy = NULL;
不需要加锁,执行效率高,线程安全的
不管是不是用都会初始化,浪费内存
class SingletonHungry{
private:
SingletonHungry(){
std::cout << "single hungry!" << std::endl;
}
public:
static SingletonHungry* getInstatce(){
return hungry;
}
//SingletonHungry类退出以后会自动析构free_single,
//从而调用FreeSingle的析构函数来释放单例
//其实类退出时会自动释放单例不需要该类
class FreeSingle{
~FreeSingle(){
if( NULL != hungry ){
delete hungry;
hungry = NULL;
}
}
};
private:
static SingletonHungry* hungry;
static FreeSingle free_single;
};
//类外初始化
SingletonHungry* SingletonHungry::hungry = new SingletonHungry;
// 局部静态变量
class Singleton{
public:
// 使用指针而不是引用是为了避免拷贝构造函数进行拷贝
// Singleton single = Singleton::getInstance();
static Singleton* getInstance(){
static Singleton instance;
return instance;
}
private:
Singleton(){
std::cout << "局部静态方式" << std::endl;
}
// 如果需要getInstance 返回引用,
// 也可以通过重载赋值运算符和拷贝构造函数,这两个函数不需要具体的实现
Singleton(Singleton const & single);
Singleton& operator = (const Singleton& single);
};
class SingletonMulThread{
private:
SingletonMulThread(){
std::cout << "single MulThread!" << std::endl;
}
public:
static SingletonMulThread* getInstatce(){
if( NULL == single_multhread ){
std::lock_guard lock(mutex);
if( NULL == single_multhread ){
single_multhread = new SingletonMulThread;
}
}
return single_multhread;
}
private:
static SingletonMulThread* single_multhread;
static mutex mutex;
};
//类外初始化
SingletonMulThread* SingletonMulThread::single_multhread = NULL;
mutex SingletonMulThread::mutex;
一般情况下,为了实现单例我们都会想到使用 static 成员,下面#1是最基本的方式;
class Singleton{
private:
Singleton(){};
virtual ~Singleton(){};
public:
Singleton *Instance();
protect:
static Singleton *_instance;
};
//Singleton.h
Singleton *Singleton::instance()
{
if(NULL == _instance){
_instance = new Singleton();
}
return _instance;
}
//Singleton.cpp
/*
构造时机: 运行时生成;
对象位置: 堆
资源释放: new的单例对象,没有时机去释放;
线程安全: 否; ---在单例构造过程可能重复,造成内存泄露;
*/
在#1的基础上解决存在的两个问题;
如果单例对象的构造实在运行时之前(也就是程序静态变量初始化时完成)就可以避免线程安全的问题;
class Singleton{
public:
static Singleton *instance();
private:
Singleton();
virtual ~Singleton();
Singleton(const Singleton&){};
Singleton& operator=(const Singleton&){};
private:
class CGarbo{
public:
~CGarbo()
{
if(Singleton::m_pInstance){
delete m_pInstance;
}
}
};
private:
static Singleton *m_pInstance;
static CGarbo Garbo;
};
//Singleton.h
Singleton::CGarbo Singleton::Garbo;
Singleton* Singleton::m_pInstance = new Singleton();
Singleton::Singleton()
{
printf("contructure funcation\n");
}
Singleton::~Singleton()
{
printf("deconstructure funcation\n");
}
Singleton* Singleton::instance()
{
return m_pInstance;
}
//Singleton.cpp
构造时机: 初始化时生成;
对象位置: 堆
资源释放: 通过一个成员的析构函数来释放单例对象,; 非常巧妙, 但是m_pInstance指针和 Garbo两个成员的析构是否有先后顺序,如果指针先被释放(指针变量变成NULL?)那么单例对象还是没有机会被释放; ---找时间确认一下,然后更新一下这个结果;
线程安全: 是; ---初始化过程,没有线程竞争;
对比以上两种方式,可以看出静态初始化的时候构造单例对象,能够比较好的解决线程安全的问题; 但是资源释放的需要通过曲线救国的方式来解决;
那么能不能把单例对象也生成在静态区呢?这样释放的问题就可以由操作系统自动完成;
class Singleton{
public:
static Singleton *instance();
private:
Singleton();
virtual ~Singleton();
Singleton(const Singleton&){};
Singleton& operator=(const Singleton&){};
private:
static Singleton m_instance;
};
//Singleton.h
Singleton Singleton::m_instance;
Singleton::Singleton()
{
printf("contructure funcation\n");
}
Singleton::~Singleton()
{
printf("deconstructure funcation\n");
}
Singleton *Singleton::instance()
{
return &m_instance;
}
//Singleton.cpp
构造时机: 初始化时生成;
对象位置: 静态区
资源释放: 在程序结束时 自动释放静态区的 成员变量
线程安全: 是;
注意: 静态成员的初始化需要放到类外完成; 那么是否可以把静态对象在成员函数instance()内部生成呢?
class Singleton{
public:
static Singleton *instance();
private:
Singleton();
virtual ~Singleton();
Singleton(const Singleton&){};
Singleton& operator=(const Singleton&){};
};
//Singleton.h
Singleton::Singleton()
{
printf("contructure funcation\n");
}
Singleton::~Singleton()
{
printf("deconstructure funcation\n");
}
Singleton *Singleton::instance()
{
static Singleton ins;
return &ins;
}
//Singleton.cpp
构造时机: 运行时生成; ---参考链接2 ; --对于C++的局部类对象,是在函数第一次调用时生成;
对象位置: 静态区
资源释放: 在程序结束时 自动释放静态区的 成员变量
线程安全: 是(C++11); ---参考链接2,, C++11标准针对局部静态对象的构造能保证线程安全(待查);
综合以上4中方式,单例对象的释放都是在程序结束时释放,
如果要求能够提供接口随时释放对象,那么就必须构造在堆上,然后提供显式的destroy接口;
#ifndef __MUTEX_H__
#define __MUTEX_h__
#include
class Mutex{
private:
pthread_mutex_t m_mutex;
public:
Mutex();
virtual ~Mutex();
private:
Mutex(const Mutex&){};
Mutex& operator=(const Mutex&){};
public:
int lock();
int unlock();
int trylock();
};
#endif //__MUTEX_H__
//Mutex.h
#include "Mutex.h"
Mutex::Mutex()
{
pthread_mutex_init(&m_mutex, NULL);
}
Mutex::~Mutex()
{
pthread_mutex_destroy(&m_mutex);
}
int Mutex::lock()
{
return pthread_mutex_lock(&m_mutex);
}
int Mutex::unlock()
{
return pthread_mutex_unlock(&m_mutex);
}
int Mutex::trylock()
{
return pthread_mutex_trylock(&m_mutex);
}
//Mutex.cpp
//单例类
#ifndef __SINGLETON_H__
#defile __SINGLETON_H__
#include "Mutex.h"
class Singleton{
public:
static Singleton *instance();
static void destroy();
private:
Singleton();
virtual ~Singleton();
Singleton(const Singleton&){};
Singleton& operator=(const Singleton&){};
private:
static Singleton *m_pInstance;
static Mutex m_Mutex;
};
#endif //__SINGLETON_H__
//Singleton.h
Singleton* Singleton::m_pInstance = NULL;
Mutex Singleton::m_Mutex;
Singleton::Singleton()
{
//do something
}
Singleton::~Singleton()
{
//do something
}
Singleton* Singleton::instance()
{
if(NULL == m_pInstance){
m_Mutex.lock();
if(NULL == m_pInstance){
m_pInstance = new Singleton();
}
m_Mutex.unlock();
}
return m_pInstance;
}
void Singleton::destroy()
{
if(m_pInstance){
m_Mutex.lock();
if(m_pInstance){
delete m_pInstance;
m_pInstance = NULL;
}
m_Mutex.unlock();
}
}
//Singleton.cpp
当然 也可以吧 静态成员指针放到接口函数里面作为局部静态变量 和局部静态对象;