设计模式是代码总结的经验,用来解决一类问题。
单例类有两个特点:
- 保证全局只有一个唯一实例
- 提供了方便获取唯一实例的接口
单例模式又分为懒汉模式和饿汉模式:(一般用在高并发环境下,所以保证线程安全并且高效很重要)
懒汉模式:直到第一次调用接口才产生实例对象 // 懒加载,与COW思想一致,用到的时候才处理,提高效率
饿汉模式:在一开始(进入main函数前)就创建一个实例 // main函数之前只有一个主线程,不存在线程安全问题class Singleton { public: static Singleton* GetInstence() { if (_sInstance == NULL) // 双重检查,保证高效,避免每次获取实例对象都要加锁 { // RAII 资源获取就是初始化:保证在任何情况下,使用对象时先构造对象,最后析构对象 lock_guard<mutex> l(lock); // RAII,new 抛异常后,保证锁被释放 // lock.lock(); // 线程安全 if (_sInstance == NULL) // 实现单例 { Singleton* tmp = new Singleton(); // 1.分配空间,2.掉构造函数,3.赋值 //加内存栅栏防止优化顺序 MemoryBarrier(); _sInstance = tmp; } // lock.unlock(); } return _sInstance; } static Delete() { lock_guard<mutex> l(lock); if (_sInstence != NULL) { delete _sInstence; _sInstence = NULL; } } void Print() const { cout << _data << endl; } private: // 构造函数限定为私有,限制只能在类里创建对象(全局除外) Singleton() : _data(0) {} Singleton(const Singleton&); // 防拷贝 Singleton& opsrator=(const Singleton& s); static mutex lock; // 静态私有:通过调用静态成员函数获取对象实例 static Singleton* _sInstance; int _data; }; mutex Singleton::lock; Singleton* Singleton::_sInstance = NULL;
缺陷:Singleton构造函数中可能创建了线程,这样就在main函数之前创建了线程,可能引发一些问题,因为main函数之前做的是一些初始化准备工作
第一种:
class Singleton { public: static Singleton* GetInstence() { assert(_sInstance != NULL); return _sInstance; } void Print() const { cout << _data << endl; } private: Singleton() : _data(0) {} Singleton(const Singleton&); // 防拷贝 Singleton& opsrator=(const Singleton& s); static Singleton* _sInstance; int _data; }; Singleton* Singleton::_sInstance = new Singleton;
第二种:class Singleton { public: static Singleton* GetInstence() { static Singleton tmp; return &tmp; } void Print() const { cout << _data << endl; } private: Singleton() : _data(0) {} Singleton(const Singleton&); // 防拷贝 int _data; };
实例销毁:这几种方法中,有些调用了new操作符实例化对象;我们一般的编程管你是,new操作是要与delete操作进行匹配的,这种观念是正确的。再第一个实现中,添加了一个Delete的static函数,这也是最简单,最普通的处理方法了;但是,很多时候,我们很容易忘记调用Delete函数,所以可以考虑RAII,类似于智能2指针的方式去处理。
但是在实际项目中,特别是客户端开发,其实是不在乎这个实例的销毁的。因为,全局就这么一个变量,全局都要用,它的声明周期伴随着软件的生命周期,软件结束了,它也就自然而然的结束了,因为一个程序关闭之后,它会释放它占用的内存资源,所以,也就没有所谓的内存泄漏了。但是,有些情况下,是必须需要进行实例销毁的:在类中,有一些文件锁,文件句柄,或是数据库连接等等,这些随着程序的关闭不会立即关闭的资源,必须要在程序关闭前,进行手动释放。
单例模式
最新推荐文章于 2024-04-25 23:15:31 发布