单例模式是设计模式中比较简单的一种。适合于一个类只有一个实例的情况,比如窗口管理器,打印缓冲池和文件系统,它们都是原型的例子。典型的情况是,那些对象的类型被遍及一个软件系统的不同对象访问,因此需要一个全局的访问指针,这便是众所周知的单例模式的应用。
单例模式要保证的就是全局只有一个对象存在;所以很容易就能想到把构造析构定义为protected或者private,这样类外无法访问,就无法再定义对象了;
而懒汉和饿汉其本质也是这个样子,只是实现过程中有不一样而已;
懒汉模式
所谓的懒汉就是比较懒,我上来先不定义对象,在你要的时候我再去定义这个唯一对象,而之后来的只需要判断对象存不存在就好了;
class Singleton
{
public:
static Singleton* GetInstance()
{
if (_inst == NULL)//判断不存在就定义
{
Singleton* tmp = new Singleton;
_inst = tmp;
}
}
return _inst;
}
private:
Singleton()//造析构都定义为私有,类外无法再定义对象
{}
~Singleton()
{}
//防拷贝
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
static Singleton* _inst;
};
这样的代码在单线程下是没有任何问题的,但是一但放到多线程下,就会有问题,因为我们不能确保只有一个对象的基本原则了,所以必须要考虑的就是加锁,保证互斥,每次只有一个进程可以进来判断;
static mutex _mtx;
if (_inst == NULL)
{
lock_guard<mutex> lock(_mtx);//c11 lock_guard互斥自动上锁,lock_guard析构时,同时把互斥解锁。
if (_inst == NULL)
{
Singleton* tmp = new Singleton;
_inst = tmp;
}
}
为了防止一个进程拿到锁之后出意外,跳出,所以我们给锁封装了一层RAII;
class Lock
{
public:
Lock(mutex& mtx)
:_mtx(mtx)
{
_mtx.lock();
}
~Lock()
{
_mtx.unlock();
}
protected:
Lock(const Lock&);
Lock& operator=(const Lock&);
private:
mutex& _mtx;
};//设计RAII防止死锁
这样懒汉模式 就完成了;
懒汉总体代码
饿汉模式
饿汉模式就是我一上来就先定义好对象,你需要的时候我直接给你就好了,有了上面的懒汉模式,饿汉应该能更好理解,就是直接定义,你要的时候我给你就好了;
class Singleton
{
public:
static Singleton& GetInstance()//直接返回给你就好
{
assert(_inst);
return *_inst;
}
protected:
Singleton()
:_a(0)
{}
Singleton(const Singleton&);//一样的防拷贝
Singleton& operator=(const Singleton&);
static Singleton* _inst;
};
Singleton* Singleton::_inst = new Singleton;//一开始就定义
并且是线程安全的,因为全局就拿一份;
还有另外一种写法:
class Singleton
{
public:
static Singleton& GetInstance()
{
static Singleton inst;
return inst;
}
protected:
Singleton()
{}
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
};
所以饿汉模式的多线程环境下是要比懒汉模式下方便许多的,但是具体应用场景还是要跟实际情况有关,
假如这个东西不是非必需的,那么就没有必要一上来就创建,完全可以等到需要的时候在创建,这样不至于浪费空间和性能;
所以各有优劣,具体情况具体分析;
懒汉代码
namespace LAZY//懒汉模式 需要的时候再定义
{
//设计一个类为单例
class Lock
{
public:
Lock(mutex& mtx)
:_mtx(mtx)
{
_mtx.lock();
}
~Lock()
{
_mtx.unlock();
}
protected:
Lock(const Lock&);
Lock& operator=(const Lock&);
private:
mutex& _mtx;
};//设计RAII防止死锁
class Singleton
{
public:
static Singleton* GetInstance()
{
if (_inst == NULL)
{
lock_guard<mutex> lock(_mtx);
if (_inst == NULL)
{
Singleton* tmp = new Singleton;
_inst = tmp;
}
}
return _inst;
}
struct GC
{
~GC()
{
DelInstance();
}
};
static void DelInstance()
{
lock_guard<mutex> lock(_mtx);
if (_inst)
{
cout << "delete" << endl;
delete _inst;
_inst = NULL;
}
}
private:
Singleton()//构造析构都定义为私有,类外无法再定义对象
{}
~Singleton()
{}
//防拷贝
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
static Singleton* _inst;
static mutex _mtx;
};
Singleton* Singleton::_inst = NULL;
mutex Singleton::_mtx;
}