1、说明
Singleton模式也即单例模式,保证一个类只有一个实例,并为该类提供一个全局访问点。在面向对象和面向过程的设计范式中,定义一个全局变量(对象)能实现这一点。但在遇到纯粹的面向对象范式时,就需要通过Singleton模式实现了。
2、原理与实现
下面是一个简单的、基础的Singleton程序。
class CSingleton
{
public:
static CSingleton* GetInstance()
{
if (_instance == NULL)
{
_instance = new CSingleton();
}
return _instance;
}
private:
CSingleton();
static CSingleton* _instance;
};
CSingleton* CSingleton::_instance = NULL;
该例子中,在公有函数Instance()中通过new方式返回一个指向唯一实例的静态的、私有的指针;同时将构造函数定义为私有,确保不能在其他地方创建实例。这种实现方式存在着两个缺陷:
(1) 找不到地方delete实例的指针,代码不严谨;
(2) 不迎合多线程问题。比如说现在有两个线程A和B,刚开始时_instance为NULL,线程A开始执行new,但是还没返回,这时如果调度器剥夺了线程A的执行开始执行线程B,线程B顺利创建了一个实例,然后又开始执行线程A,此时线程A继续执行new,又创建了另外一个实例。此时此刻,Singleton失败了。
我们知道,程序结束时系统会自动析构类的静态成员变量。利用这一特点,可以巧妙的解决上述第一个缺陷。下面是代码实现:
class CSingleton
{
private:
CSingleton(){}
public:
static CSingleton *GetInstance()
{
static CSingleton s_singleton;
return &s_singleton;
}
};
这种实现方式,十分简洁,且不用再担心delete的问题。但在编译期间会为静态数据分配较大的空间,违背了“不使用单例不浪费空间”的原则。另外,该实现方式还是无法迎合多线程问题。
3、Code - C++
基于上述出现的各种问题,下面的Singleton模式引入了auto_ptr和同步机制。
// CCriticalSection.h
#ifndef _CCRITICALSECTION_H_
#define _CCRITICALSECTION_H_
class CCriticalSection
{
public:
CCriticalSection();
~CCriticalSection();
public:
void EnterCriticalSection();
void LeaveCriticalSection();
private:
CRITICAL_SECTION m_objCriticalSection;
};
class CCriticalSectionOwner
{
public:
explicit CCriticalSectionOwner(CCriticalSection &);
~CCriticalSectionOwner();
private:
CCriticalSection &m_refCCriticalSection
};
#endif
// CCriticalSection.cpp
#include "CCriticalSection.h"
CCriticalSection::CCriticalSection()
{
::InitializeCriticalSection(&m_objCriticalSection);
}
CCriticalSection::~CCriticalSection()
{
::DeleteCriticalSection(&m_objCriticalSection);
}
void CCriticalSection::EnterCriticalSection()
{
::EnterCriticalSection(&m_objCriticalSection);
}
void CCriticalSection::LeaveCriticalSection()
{
::LeaveCriticalSection(&m_objCriticalSection);
}
CCriticalSectionOwner::CCriticalSectionOwner(CCriticalSection &refCCriticalSection)
:m_refCCriticalSection(refCCriticalSection)
{
m_refCCriticalSection.EnterCriticalSection();
}
CCriticalSectionOwner::~CCriticalSectionOwner()
{
m_refCCriticalSection.LeaveCriticalSection();
}
// CSingleton.h
#ifndef _CSINGLETON_H_
#define _CSINGLETON_H_
#include "CCriticalSection.h"
#include <memory>
using namespace std;
template <class T>
class CSingleton
{
protected:
static auto_ptr<T> m_autoptrObject;
static CCriticalSection m_objCCriticalSection;
CSingleton() { }
public:
static T* GetInstance()
{
CCriticalSectionOwner objCCriticalSectionOwner(m_objCCriticalSection);
if (NULL == m_autoptrObject.get())
{
m_autoptrObject.reset(new T());
}
return m_autoptrObject.get();
}
};
template <class T>
auto_ptr<T> CSingleton<T>::m_autoptrObject;
template <class T>
CCriticalSection CSingleton<T>::m_objCCriticalSection;
#endif