单例模式
使用场景:只有一个实例对象。
单例模式需要将默认构造函数声明为私有,这样就不会被外部new出来了,甚至可以将析构函数也声明为私有的,这样就只有自己能够删除自己了。单例模式分为饿汉模式和懒汉模式,定义如下:
class CSingleton { private: CSingleton() //构造函数是私有的 { } static CSingleton *m_pInstance = NULL; //懒汉模式 //static CSinleton *m_pInstace = new CSinleton(); //饿汉模式 public: //懒汉模式 static CSingleton * GetInstance() { if(m_pInstance == NULL) //判断是否第一次调用 m_pInstance = new CSingleton(); return m_pInstance; } //饿汉模式 //static CSingleton * GetInstance() //{ // return m_pInstance; //} static CSingleton * RealeaseInstance() { if( m_pInstance != NULL) { delete m_pInstance; m_pInstance = NULL; } } };
用户访问唯一实例的方法只有GetInstance()成员函数。如果不通过这个函数,任何创建实例的尝试都将失败,因为类的构造函数是私有的,所有GetInstance()之后的调用都返回相同实例的指针。
但是这里有一个问题,对于饿汉模式来说,多线程下就出现了问题:第一个线程进来判断m_pInstance == NULL, new出一个实例。这个时候第二个线程也进来了,判断的sInstance 也== NULL,然后也会 new 出一个实例,这样就new出了两个实例,显然这不是我们所要的单例模式了。因此,需要在代码中加锁:
static CSingleton * GetInstance() { lock(); if(m_pInstance == NULL) //判断是否第一次调用 m_pInstance = new CSingleton(); return m_pInstance; unlock();
}
但这样写的话,会稍稍映像性能,因为每次判断是否为空都需要被锁定,如果有很多线程的话,就爱会造成大量线程的阻塞。于是大神们又提出了双重锁定:
static CSingleton * GetInstance() { if(m_pInstance ==NULL) { lock(); if(m_pInstance == NULL) m_pInstance = new CSingleton(); unlock(); } return m_pInstance; }
这样只够极低的几率下,通过越过了if (m_pInstance== NULL)的线程才会有进入锁定临界区的可能性,这种几率还是比较低的,不会阻塞太多的线程,但为了防止一个线程进入临界区创建实例,另外的线程也进去临界区创建实例,又加上了一道防御if (m_pInstance== NULL),这样就确保不会重复创建了。
最后,推荐使用饿汉模式,安全,简单。