单例模式汇总
单例模式的几个深坑,你是已经否不知不觉地掉进去了:
- 对象的析构问题
- 线程安全
- 一个单例类的构造函数调用另一个单例类
区分懒汉模式和饿汉模式:
- 懒汉模式是指第一次使用的时候实例才会被构建,延迟加载,顾名思义,懒汉,特别懒,用到他,他才会加载。
- 饿汉模式是指在类装载的时候就把单例实例构建好,顾名思义,饿汉,特别能吃,一上来就吃。
首先来看一下教科书式单例模式
class Singleton{
public:
static Singleton* GetInstance()
{
if(NULL==m_instance)
{
m_instance = new Singleton();
}
return m_instance;
}
private:
Singleton(){
std::cout<<"constructor has been called\n";
}
static Singleton* m_instance;
};
Singleton* Singleton::m_instance = NULL;
我们来看一下运行结果:
构造函数只调用了一次,这个单例模式好像是成功了,但是细心的同学们有没有发现,单例实例没有被正确的释放。什么时候释放,该怎么释放?最简单的方式是添加一个destory函数,在合适的地方调用。destory()如下:
static void destory()
{
if(m_instance != NULL)
delete m_instance;
}
但是缺陷很严重,大家很容易忘记调用他。最完美的方法是让这个类自己在合适的时机析构自己。当程序结束时,系统会为我们释放所有的全局变量以及静态变量,我们刚好可以利用这一点。下面是添加垃圾回收器的单例模式:
class Singleton
{
private:
Singleton()
{
std::cout<<"constructor has been called\n";
}
static Singleton *m_instance;
class GC
{
public:
GC()
{
std::cout<<"GC constructor has been called\n";
}
~GC()
{
std::cout<<"GC desructor has been called\n";
if(Singleton::m_instance)
{
std::cout<<"delete m_instance\n";
delete Singleton::m_instance;
}
}
};
static GC gc; //当gc被析构时,delete m_instance;
public:
static Singleton * GetInstance()
{
if(m_instance == NULL)
m_instance = new Singleton();
return m_instance;
}
};
Singleton* Singleton::m_instance = NULL;
Singleton::GC Singleton::gc;
使用内嵌类GC实现了单例实例的自动释放,看起来已经不错了,但是我们不该满足于此。添加一个内嵌类让代码看起来一点儿都不优雅,添加内部类是为了解决对象的释放问题,还有什么能够实现自动释放呢,当然是牛x的智能指针了~~~,下面是智能指针版的单例模式:
class Singleton
{
public:
static std::shared_ptr<Singleton> GetInstance()
{
if(m_instance == NULL)
m_instance = std::shared_ptr<Singleton>(new Singleton);
return m_instance;
}
public:
~Singleton()//必须是public 由智能指针调用
{
std::cout<<"destructor has been called\n";
}
private:
static std::shared_ptr<Singleton> m_instance;
Singleton()
{
std::cout<<"constructor has been called\n";
}
};
std::shared_ptr<Singleton> Singleton::m_instance = NULL;
是不是清爽多了呀~~~,智能指针真乃C++程序员的一大利器,为智能指针歌功颂德的话不多说了,智能指针带来的便利,大家慢慢体会~
另外Meyers 大师在《More Effective C++》中给我们提供一种更牛掰的方法,也被称为Meyers Singleton。如下:
class Singleton
{
private:
Singleton()
{
std::cout<<"constructor has been called\n";
}
~Singleton()
{
std::cout<<"destructor has been called\n";
}
Singleton(const Singleton&);
Singleton& operator(const Singleton&);
public:
static Singleton& GetInstance()
{
static Singleton m_instance; //局部静态变量
return m_instance;
}
};
Meyers 大师提供的这种方法代码量更少,真的是非常强大,但是需要注意的是返回一个对象的引用会出现类拷贝问题,例如Singleton single = Singleton::GetInstance;破坏了单例实例的全局唯一性,所以我们必须禁用类拷贝和赋值;也可以采用下面这种方式,返回对象的指针;
class Singleton
{
private:
Singleton()
{
std::cout<<"constructor has been called\n";
}
~Singleton()
{
std::cout<<"destructor has been called\n";
}
public:
static Singleton * GetInstance()
{
static Singleton m_instance; //局部静态变量
return &m_instance;
}
};
那么到这里我们是不是就该结束了呢? No No No,这才刚刚开始~,接下来我们聊聊开篇提到的三个大坑;
请看《单例模式汇总续》