设计模式之单例模式 设计模式 设计模式简单来说就是在解决某一类问题场景时,有既定的,优秀的代码框架可以直接使用,代码更易于维护,代码的可读性,复用性,可移植性,健壮性会更好
单例模式 概念 单例模式是指在内存中只会创建一个对象,且只能创建一个对象的设计模式,在程序中多次调用同一个对象且作用相同时,为了防止多次创建对象耗费大量内存,单例模式让程序在内存只创建一个对象,所有调用的地方共享该对象。
类型 懒汉式 在真正使用该对象时才去创建该对象,因为很懒~ 懒汉式创建对象的方法是在程序使用对象前,先判断该对象是否已经实例化(判空),若已实例化直接返回该类对象,否则则先执行实例化操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 class Singleton { public : static Singleton* getInstance () { if (single == nullptr ) { single = new Singleton (); } return single; } private : Singleton (){cout << "create" << endl;}; ~Singleton () { cout << "delete" <<endl; } static Singleton* single; class CRelease { public : ~CRelease () { delete single; } }; static CRelease release; }; Singleton* Singleton::single = nullptr ; Singleton::CRelease Singleton::release;
构造函数私有化,这样用户就不能任意定义该类型的对象了 定义该类型唯一的对象 通过一个static静态成员方法返回唯一的对象实例
由于析构函数被声明为私有的,无法通过delete 来释放掉内存, 为防止内存泄漏(虽然当前进程结束的时候,系统反正会回收分配给它的所有资源,包括未回收的内存),在类内嵌套了一个类,利用static静态对象在程序结束时自动析构这么一个特征。
懒汉式如何保证只创建一个对象 若多个线程同时判断 singleton == nullptr, 则会同时创建一个对象,如何保证安全? 通过加互斥锁 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 class Singleton { public : static Singleton* getInstance () { if (single == nullptr ) { if (single == nullptr ) { single = new Singleton (); } } return single; } private : Singleton (){cout << "create" << endl;}; ~Singleton () { cout << "delete" <<endl; } static Singleton* single; class CRelease { public : ~CRelease () { delete single; } }; static CRelease release; static mutex mtx; }; Singleton* Singleton::single = nullptr ; Singleton::CRelease Singleton::release;
另一种保证线程安全且能在main结束后自动释放对象的写法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <iostream> using namespace std;class CSingleton { public : static CSingleton* getInstance () { static CSingleton single; return &single; } private : CSingleton () { cout << "CSingleton()" << endl; } ~CSingleton () { cout << "~CSingleton()" << endl;} CSingleton (const CSingleton&); }; int main () { CSingleton *p1 = CSingleton::getInstance (); CSingleton *p2 = CSingleton::getInstance (); CSingleton *p3 = CSingleton::getInstance (); return 0 ; }
对于static静态局部变量的初始化,编译器会自动对它的初始化进行加锁和解锁控制,使静态局部变量的初始化成为线程安全的操作,不用担心多个线程都会初始化静态局部变量,因此上面的懒汉单例模式是线程安全的单例模式
静态局部变量的生命周期贯穿整个程序的运行时间,但是它们的初始化是延迟的,也就是说,它们只在首次被引用时初始化。这是C++标准中静态局部变量的一个重要特性,称为“Magic Statics”(也称作“函数内的静态局部变量”或“局部静态变量”)。
当你在函数内部声明一个静态局部变量时,这个变量的存储空间在程序开始运行时就已经被分配了,但是它的初始化会被推迟到该函数首次被调用,且到达该变量声明的时候。一旦初始化完成,该变量的值就会在程序的后续调用中保持不变,直到程序结束。
静态变量*******
饿汉式 在类加载时已经创建好了该单例对象,等待程序使用 在编码时就已经指明了要马上创建这个对象,不需要等到被调用时再去创建。
1 2 3 4 5 6 7 8 9 10 11 12 13 class Singleton { public : static Singleton* getInstance () { return &single; } private : Singleton (); ~Singleton (); static Singleton single; } Singleton Singleton::single;