一、单利模式的定义
在特定的时候我们会遇到一种情况:一个类只能有一个对象被实例化,这个时候我们就可以使用单例模式。
单利模式通过类本身来管理其唯一实例。在设计这个类的时候,让它只能产生一个实例并提供对此实例的全局访问。所以单例模式的两个要素分别是:
1.确保一个类只有一个实例被创建。2.提供一个对实例的全局访问指针。
二、常见单例模式的实现方法
1.懒汉式:class Singleton1{public :static Singleton1 * GetInstance()//获取指向该类对象的指针,//因为在类外不能创建对象,所以要将该函数声明为static的,//使得在类外可以使用类的作用域限定符来获取{if ( NULL == _Instance) / /和静态成员变量一起保证只产生一份实例_Instance = new Singleton1 ();return _Instance;}private :Singleton1 (){};static Singleton1 * _Instance;//静态成言变量 不管有多少个对象的实例 静态成员变量只有在静态全局区的一份};Singleton * Singleton1 ::_Instance = NULL ; //静态成员变量需要在类外定义解释:
1) 因为只能产生一个实例所以类的构造函数要被声明为私有的----防止在类外任意地方可以生成该类的对象。
2) 类外不能实例化出该类的对象,所以要类内定义一个公有的静态成员函数调用构造函数返回对象实例的地址当需要使用对象时,使用类的作用域限定符引用该静态方法 。3) 因为类的静态成员变量在内存的静态全局区存储,所有类的对象共享一份定义一个类对象类型的静态指针如此以来当类的第一个实例构造完成后再次调用GetSingleton()方法对象指针已存在直接返回第一次构造出的对象的地址。该代码的缺陷:
1)new 出来的空间并没有被delete释放 出现了内存泄漏。
2)没有注意到线程安全的问题。假设现在有两个线程,线程①引用类的静态方法—>判断静态成员变量为NULL,这时线程①暂停,线程②也引用类的静态方法—>判断静态成员变量为NULL,创建对象(对象①),然后线程②暂停,线程①继续执行,创建对象(对象②)。——->这和单例模式的要求(只能创建一个对象)难道不是矛盾了吗?所以为了保证在多线程环境下我们还是能够得到类型的一个实例,我们就需要为其加上一把同步锁。。。
为解决缺陷的新代码![]()
![]()
解释:1)相较于第一种版本 该版本增加了线程互斥锁保证了判断对象指针是否为空和开辟对象实例的空间这两步为原子操作2)在类作用域内定义了一个专门用来析构该类对象的类 该类是静态的。在进程结束后系统会释放所有静态全局区的属于该进程的数据这时会调用该对象析构函数 析构函数内释放对象
进一步优化 这次利用C++标准库中的lock_guard<>对象加锁实现双重检查,为什么是双重检查呢,就是为高效,避免每一次都需要加锁解锁,而只需要第一次创建对象的时候加锁。class Singleton{public :static Singleton * GetInstance(){if (_Instance == NULL ){//一重检查std:: lock_guard < mutex > lk ( mutex );if (_Instance == NULL )//二重检查_Instance = new Singleton ();}return _Instance ;}static void DelInstance(){std:: lock_guard < mutex > lk ( mutex );if (_Instance){delete _Instance;_Instance = NULL ;}}private :Singleton ():_data(0){};//class Dele//{//public:// ~Dele()// {// std::lock_guard<mutex> lk(mutex);// if (Singleton::_Instance)// delete Singleton::_Instance;// }//};int _data;static mutex _mutex;Singleton ( const Singleton &);Singleton & operator= ( const Singleton &);//static Dele _Dele;static Singleton * _Instance; //静态成言变量 不管有多少个对象的实例 静态成员变量只有在静态全局区的一份};Singleton * Singleton ::_Instance = NULL ;mutex Singleton ::_mutex;
2.饿汉式:class Singleton{public :static Singleton * GetInstance(){static Singleton _Instance;return &_Instance;}private :int _data;Singleton ( const Singleton &);Singleton & operator= ( const Singleton &);Singleton ():_data(0){};};在饿汉模式下,类的唯一实例是在类创建的时候就被创建出来,因为这时候Getlnstance方法内部有了一个静态的类的实例。每次调用该方法时都返回这个静态实例的地址,所以不存在内存泄漏和安全问题;