服务器程序里很多时候都需要使用单例,目前我使用有两种方式:
方式一:
static CWanClient& Instance()
{
static CWanClient m_cWanClient;
return m_cWanClient;
}
静态成员方式调用,看上去也没什么问题
方式二:
/*
* 使用的时候只需要单件类继承此模板即可。
* class CTest : public Singleton<CTest>
* {...};
*
* 程序退出时需要调用Release()释放指针
*/
template<class T>
class Singleton
{
private:
/**
* \brief 拷贝构造函数,没有实现,禁用掉了
*
*/
Singleton(const Singleton&);
/**
* \brief 赋值操作符号,没有实现,禁用掉了
*
*/
const Singleton & operator= (const Singleton &);
public:
static T* GetMe()
{
if (!_instance)
{
_instance = new T;
}
return _instance;
}
static void Release()
{
if ( NULL != _instance )
{
delete _instance;
_instance = NULL;
}
}
protected:
// 使用保护构造是为了用户不能在栈上声明一个实例
Singleton() {}
private:
static T* _instance; // 实例静态指针
};
// 静态实例指针初始化
template <class T> T* Singleton<T>::_instance = NULL;
使用时:
class CWanClient : public Singleton<CWanClient>
两种方式一看就明白,第二种方式是new出来的对象,需要手动释放。
这两种方式的代码若是放在exe中,好像区别不太大,也就是存储位置不一样,但是如果放在作为dll被调用时,问题就来了,
很多DLL调用方式,都期望接口是 new/delete (分配/释放),这时,如果使用的是第一种静态成员的方式,则就会导致重复调用此dll时,不会再次进入对像的构造和析构函数了。
后面想了想,这也是需要看实际情况来处理,若所有的初始化和释放都是单独的函数,并非构造和析构,那应该是没有问题的,手动调用就行了,但是当工程越来越大,DLL库越来越多的时候,这样的问题就很难查出来了,再者说,如果使用NEW方式的单例,是否还能避免栈溢出呢?
得出总结,还是使用new方式的单例更靠谱一些,无非多了一次手动释放而已。