单例模式,即保证程序中一个类只有一个实例,并提供一个全局访问点。
class CSingleton
{
private:
CSingleton() {} // 私有构造函数
static CSingleton *m_pInstance; // 唯一实例
public:
static CSingleton *GetInstance()
{
if (m_pInstance == NULL) // 判断是否第一次调用
m_pInstance = new CSingleton(); // 懒惰初始化,函数首次被访问时创建
return m_pInstance;
}
};
单例类CSingleton有以下特征:
私有的指向唯一实例的静态指针;
公有的获取唯一实例的静态函数;
私有构造函数。
多线程问题,上述代码不能保证只实例化一次。可以在判断实例是否为空时直接加锁保证,但是这样效率太低,因为只有第一次需要加锁,实例化后就不需要了,每次都加锁没有必要。可以使用双重判断来解决。
拷贝和赋值问题,我们要禁止拷贝和赋值,防止多个实例。显式声明拷贝构造函数和赋值函数为私有,且只声明不实现。
实例释放问题,一般不需要关注,因为只有一个实例,直到进程结束空间被释放,不会有内存泄漏。如果需要关注,可以在类中增加一个内部类,并增加该类的静态对象为成员。该内部类的析构函数中对单例实例进行释放。
class CSingleton
{
private:
CSingleton() {}
static CSingleton *m_pInstance;
class CGarbo //它的唯一工作就是在析构函数中删除CSingleton的实例
{
public:
~CGarbo()
{
if (CSingleton::m_pInstance)
delete CSingleton::m_pInstance;
}
};
static CGarbo Garbo; // 定义一个静态成员变量,程序结束时,系统会自动调用它的析构函数
public:
static CSingleton * GetInstance()
{
if (m_pInstance == NULL) //判断是否第一次调用
m_pInstance = new CSingleton();
return m_pInstance;
}
};
一般来讲,如下单例即可使用。
class Lock
{
private:
CCriticalSection m_cs;
public:
Lock(CCriticalSection cs) : m_cs(cs)
{
m_cs.Lock();
}
~Lock()
{
m_cs.Unlock();
}
};
class Singleton
{
private:
Singleton();
Singleton(constSingleton &);
Singleton& operator = (const Singleton &);
public:
static Singleton *Instantialize();
static Singleton *pInstance;
static CCriticalSection cs;
};
Singleton* Singleton::pInstance = 0;
Singleton* Singleton::Instantialize()
{
if (pInstance == NULL)
{ // double check
Locklock(cs); // 用lock实现线程安全,用资源管理类,实现异常安全
// 使用资源管理类,在抛出异常的时候,资源管理类对象会被析构,析构总是发生的无论是因为异常抛出还是语句块结束。
if (pInstance == NULL)
{
pInstance = new Singleton();
}
}
return pInstance;
}