在《C++中的单例模式及按需释放模型》系列文中已经对按需释放单例模型进行了详细描述,其中也提到了是模仿auto_ptr引入单例类实例获取器来控制单例类实例的生命周期,实现按需施放的,但是没有给出运算符重载的版本,本文对实例获取器给出运算符重载版本,使单例模型使用起来更加容易方便。
不多说,直接给出单例类实例获取器的代码
template <typename T>
class Singleton_ptr
{
public:
Singleton_ptr(void)
{
if (m_pInstance == NULL)
{
try
{
m_pInstance = new T();
}
catch (...) //防止new分配内存可能出错的问题,内存分配错误异常为std::bad_alloc
{
m_pInstance = NULL;
}
}
m_uiReference++;
}
~Singleton_ptr(void)
{
m_uiReference--;
if (m_uiReference == 0)
{
if (m_pInstance != NULL)
{
delete m_pInstance;
m_pInstance = NULL; //非常重要,不然下次再次建立单例的对象的时候错误
}
}
}
public:
T *GetInstance() const throw()
{
return m_pInstance;
}
T& operator*() const
{
return *m_pInstance;
}
T *operator->() const throw()
{
return m_pInstance;
}
operator T *() const throw() //转换操作符,转化为具体类的指针类型
{
return m_pInstance;
}
private:
static T *m_pInstance;
static unsigned int m_uiReference;
};
template <typename T>
T *Singleton_ptr<T>::m_pInstance = NULL;
template <typename T>
unsigned int Singleton_ptr<T>::m_uiReference = 0;
主要改变就是重载了"*"、“->"操作符,使用这些操作符可以直接操作单例对象,并重载了转换操作符,直接转换成单例类的指针类型。
对于类似如下的单例类
class SingletonExampleOne
{
friend Singleton_ptr<SingletonExampleOne>::Singleton_ptr();
private:
SingletonExampleOne(void);
public:
~SingletonExampleOne(void);
public:
int GetVariable();
void SetVariable(const int nValue);
private:
int m_nVariable;
};
可以通过如下多种方式使用单例类
Singleton_ptr<SingletonExampleOne> pseSingleton1;
//使用->操作符直接操作SingletonExampleOne的方法,最标准方便的用法
i = pseSingleton1->GetVariable();
//使用*操作符获得SingletonExampleOne实例并操作其方法
(*pseSingleton1).SetVariable(10);
//使用成员函数获得SingletonExampleOne实例指针
SingletonExampleOne *pp1 = pseSingleton1.GetInstance();
//使用转换操作符获得SingletonExampleOne实例指针
SingletonExampleOne *pp2 = pseSingleton1;
正如代码中注释一样,可以使用"->"、"*"操作符直接调用单例类的方法,可以通过单例类实例获取器方法GetInstance直接得到单例类SingletonExampleOne的实例指针,也可以使用转换操作符直接将单例类实例获取器实例转换为单例类SingletonExampleOne的实例指针,然后再使用单例类,这样使用过程中代码更加简洁灵活了。
真实的测试例子如下
int _tmain(int argc, _TCHAR* argv[])
{
int i;
{
Singleton_ptr<SingletonExampleOne> pseSingleton1;
//使用->操作符直接操作SingletonExampleOne的方法,最标准方便的用法
i = pseSingleton1->GetVariable();
cout << i << endl;
//使用*操作符获得SingletonExampleOne实例并操作其方法
(*pseSingleton1).SetVariable(10);
//使用成员函数获得SingletonExampleOne实例指针
SingletonExampleOne *pp1 = pseSingleton1.GetInstance();
//使用转换操作符获得SingletonExampleOne实例指针
SingletonExampleOne *pp2 = pseSingleton1;
i = pp2->GetVariable();
cout << i << endl;
{
//在pseSingleton1生存期内,再次定义SingletonExampleOne类型实例获取器
//其指向的SingletonExampleOne实例同pseSingleton1指向的实例
Singleton_ptr<SingletonExampleOne> pseSingleton2;
//pp3和pp1、pp2指向的是同一个SingletonExampleOne实例
SingletonExampleOne *pp3 = pseSingleton2;
i = pp3->GetVariable();
cout << i << endl;
}
}
//pseSingleton1、pseSingleton2释放后,SingletonExampleOne实例也释放了
//下面重新定义SingletonExampleOne的实例获取器,SingletonExampleOne实例重新被创建
Singleton_ptr<SingletonExampleOne> pseSingleton3;
i = pseSingleton3->GetVariable();
cout << i << endl;
char c;
cin >> c;
return 0;
//程序退出时SingletonExampleOne的实例跟随实例获取器对象pseSingleton3一起被释放
}
代码中演示了多种使用单例类的方法,都比较简单,要比《C++中的单例模式及按需释放模型》原文中的方法要简单。
运行结果是0 10 10 0,说明了单例类能够跟随单例类实例获取器按需释放,当生命周期最长的一个单例类实例获取器释放后单例类也跟随一起释放,即按需释放的效果,只要能控制好单例类实例获取器的生命周期,就能控制好单例类的生命周期;
既然是单例模型,当定义了一个单例类实例获取器后,在其生命周期内,不管再通过新的单例类实例获取器获取多少次单例类,其单例对象总是唯一的,即单例。
改进过的代码示例在以下地址可以下载到http://download.csdn.net/detail/gogogo/3881956,例子中同时给出了多线程的改进版,有兴趣的读者可以下载看看。