设计模式之单例模式
设计模式
设计模式简单来说就是在解决某一类问题场景时,有既定的,优秀的代码框架可以直接使用,代码更易于维护,代码的可读性,复用性,可移植性,健壮性会更好
单例模式
概念
单例模式是指在内存中只会创建一个对象,且只能创建一个对象的设计模式,在程序中多次调用同一个对象且作用相同时,为了防止多次创建对象耗费大量内存,单例模式让程序在内存只创建一个对象,所有调用的地方共享该对象。
类型
懒汉式
在真正使用该对象时才去创建该对象,因为很懒~
懒汉式创建对象的方法是在程序使用对象前,先判断该对象是否已经实例化(判空),若已实例化直接返回该类对象,否则则先执行实例化操作。
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;
|