(如有错误,请联系我更正,以免误导他人!)
C++中单例模式的应用非常广泛,在我们平时使用的windows操作系统中就存在大量的单例应用。如:回收站、任务管理器、文件资源管理器等。
单例模式的实现也有许许多多的方法,每种实现方法都有各自的优点和实用场景。
实现一:
class Singleton {
public:
static Singleton* getInstance();
~Singleton();
private:
Singleton();
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
private:
static Singleton* m_Instance;
};
Singleton* Singleton::m_Instance = nullptr;
Singleton::Singleton() {}
Singleton::~Singleton() {}
Singleton* Singleton::getInstance() {
if (m_Instance == nullptr)
m_Instance = new Singleton;
return m_Instance;
}
分析
优点:1、实例在首次调用getInstance时才创建
缺点:1、程序结束时析构函数不被调用,需要手动delete释放内存并关闭/恢复类中操作(主要是程序结束后还是不被关闭的操作,如:数据库连接、文件锁、注册表操作)
2、线程不安全,在多线程情况下可能会产生多个实例(下面是break在QQ刚登入没多久时查看的线程数,82个。。。试想如果82个线程同时调用getInstance)
实现二:在实现一的基础上修改getInstance函数如下:
Singleton* Singleton::getInstance() {
if (m_Instance == nullptr)
{
Lock();//线程锁
if (m_Instance == nullptr)
m_Instance = new Singleton;
UnLock();
}
return m_Instance;
}
分析
在实现一的基础上解决了线程不安全问题,但加锁操作使程序在性能上有所下降(当数据量大的时候不推荐使用)
实现三:
class Singleton {
public:
static Singleton* getInstance();
~Singleton();
private:
Singleton();
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
};
Singleton::Singleton() {}
Singleton::~Singleton() {}
Singleton* Singleton::getInstance() {
static Singleton m_Instance;
return &m_Instance;
}
分析
使用了局部静态变量。在实现二的基础上解决了性能下降的问题,但实例只能在程序结束时销毁,从程序开始到程序结束一直占用内存。换一种思考方式,相对于前面两种实现,实现三能够省去程序员的维护工作,不用手动delete释放内存。
实现四:
class Singleton {
public:
static Singleton* getInstance();
~Singleton();
private:
Singleton();
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
static Singleton m_Instance;
};
Singleton Singleton::m_Instance;
Singleton::Singleton() {}
Singleton::~Singleton() {}
Singleton* Singleton::getInstance() {
return &m_Instance;
}
分析
与实现三相比,实现四中实例为静态成员变量,在程序的开始初始化。
实现五:
class Singleton {
public:
static Singleton* getInstance();
static void destoryInstance();
private:
~Singleton();
Singleton();
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
static Singleton* const m_Instance;
};
Singleton* const Singleton::m_Instance=new Singleton;
Singleton::Singleton() {}
Singleton::~Singleton() {}
void Singleton::destoryInstance() {
if (m_Instance != nullptr)
{
delete m_Instance;
const_cast(m_Instance) = nullptr;
}
}
Singleton* Singleton::getInstance() {
return m_Instance;
}
分析
实例在程序开始初始化,避免了实现一中的线程不安全问题。同实现一、二,相对于实现三、四而言,我们需要手动释放内存。
实现六:
class Singleton {
public:
static Singleton* getInstance();
static void destoryInstance();
private:
~Singleton();
Singleton();
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
private:
class GC {
public:
~GC()
{
destoryInstance();
}
};
private:
static Singleton* const m_Instance;
static GC gc;
};
Singleton* const Singleton::m_Instance = new Singleton;
Singleton::GC Singleton::gc;
Singleton::Singleton() {}
Singleton::~Singleton() {}
void Singleton::destoryInstance() {
if (m_Instance != nullptr)
{
delete m_Instance;
const_cast(m_Instance) = nullptr;
}
}
Singleton* Singleton::getInstance() {
return m_Instance;
}
分析
在实现五的基础上添加了私有内部类GC,创建了私有静态成员变量gc。这里利用了C++的RALL机制。当程序结束时,通过释放静态成员变量gc来释放单例m_Instance,并在单例的析构中做一些对类中其他操作的释放。这里相对于实现五来说添加了实现三、四具备的自动回收机制。利用实现六,我们可以在需要释放的时候手动释放单例,也可以让程序在结束时自动回收单例(防止程序员忘记释放内存,就像我们平时忘记delete一样)。我们在实现一个有很多不可预料的因素的功能时,这么做是很有帮助的,我们可以通过对不可预测的因素进行if判断来决定是否提前释放单例。
可见单例模式的实现多种多样,各有千秋。我们需要根据功能需求来选择合适我们的实现方法。
如果有更多更好的单例模式实现方法,小伙伴们不妨拿出来分享一下,谢谢啦!