C++实现懒汉式单例模式
来源:互联网 发布:dede cms流量整站源码 编辑:程序博客网 时间:2024/06/05 09:36
单例模式无论在生活中还是在工程中都有很广泛的应用,在C++项目中,很多时候我们只希望整个工程中某个类仅有一个实体对象,设计这种类的时候就需要使用单例模式来设计。下面是实现的一个懒汉式单例模式的代码:
#include <iostream>#include <cstdio>using std::cout;using std::endl;class Singleton { private : static Singleton* p_obj; Singleton(void){ } public : static Singleton* GetInstance(void){ if(p_obj == NULL){ p_obj = new Singleton(); cout << "New Singleton();" << endl; return p_obj; } } ~Singleton(void){ if(p_obj!=NULL){ delete p_obj; p_obj = NULL; cout << "~Singleton" << endl; } }};Singleton* Singleton::p_obj = NULL;void run(void){ Singleton* s1 = Singleton::GetInstance(); Singleton* s2 = Singleton::GetInstance(); cout << "ADDR s1:" << s1 << endl; cout << "ADDR s2:" << s2 << endl; }int main(){ run(); cout << "Press enter to continue..." << endl; getchar(); return 0;}
在设计类的时候,声明了一个static Singleton类型的指针在类的私有成员区,需要注意的是,这个指针的内存单元并不会在对象中开辟,需要程序员自己在全局定义一个Singleton指针,如果不是单例模式的类,这种static类型的成员是每一个对象共享的,即所有的对象都可以访问在全局数据区的这一段static内存。
在类私有成员区还定义了构造函数,显然地,这样设计时不想让程序员可以直接创建Singleton对象,而是需要创建Singleton指针使用GetInstance方法去创建一个对象。这里需要我们知道C++编译器的一个特性:当程序员在设计类的时候,没有显示地声明构造函数,编译器会默认提供一个空的构造函数。这种懒汉式单例模式的实现,就是利用了C++的这一特性,将构造函数声明在类私有成员区,如果程序员在外部创建Singleton对象,编译器将报错:Singleton成员函数时私有的,不可访问。
如果想要调用Singleton类中的GetInstance函数创建对象,首先会判断一下p_obj指针是不是为空,即是不是还没有开辟过这个对象,如果确实目前还没有开辟过这个对象,那么使用new关键字在堆空间中开辟一段Sngleton大小的内存给申请者,而如果程序中早已存在Singleotn对象,则把已经存在的Singleton对象在堆空间中的地址返回给申请者。
其实这段程序是有漏洞的,在类中实现的析构函数并不会释放堆内存,因为它根本就没有被调用。这就造成了堆内存泄露的灾难。不能够在析构中释放内存,而是需要调用者手动地释放堆内存。改进这个漏洞后的代码如下:
#include <iostream>#include <cstdio>using std::cout;using std::endl;class Singleton { private : static Singleton* p_obj; Singleton(){ } public : static Singleton* GetInstance(){ if(p_obj == NULL){ p_obj = new Singleton(); cout << "New Singleton();" << endl; return p_obj; } }};Singleton* Singleton::p_obj = NULL;void run(){ Singleton* s1 = Singleton::GetInstance(); Singleton* s2 = Singleton::GetInstance(); cout << "ADDR s1:" << s1 << endl; cout << "ADDR s2:" << s2 << endl; delete s1;}int main(){ run(); cout << "Press enter to continue..." << endl; getchar(); return 0;}
显然,改进了的代码在单线程系统中不会再造成堆内存泄露。为什么要强调一下是单线程的系统中呢?因为它在多线程的系统中还是可能出问题,想象一下,同时两个线程运行到了if(p_obj == NULL),这时候会怎样?显然,会在堆内存中申请两个Singleton大小的内存段。然而我们只释放了一个,想象中他们是同一段,这就造成了泄露了一段Singleton大小的内存。改进这个漏洞的方法是在if(NULL != p_obj)前后加锁,改进如下:
#include <iostream>#include <cstdio>using std::cout;using std::endl;class Singleton { private : static Singleton* p_obj; Singleton(){ } public : static Singleton* GetInstance(){ lock(); if(p_obj == NULL){ p_obj = new Singleton(); cout << "New Singleton();" << endl; return p_obj; } unlock(); }};Singleton* Singleton::p_obj = NULL;void run(){ Singleton* s1 = Singleton::GetInstance(); Singleton* s2 = Singleton::GetInstance(); cout << "ADDR P1:" << s1 << endl; cout << "ADDR P2:" << s2 << endl; delete s1;}int main(){ run(); cout << "Press enter to continue..." << endl; getchar(); return 0;}
然而这样做的在线程很多的时候会影响代码的效率,试想当多个线程都想要申请这么这段内存的时候,都被调度器阻塞,堆在一起等待,这是一件多可怕的事情。为了提高代码的运行效率,可以使用双重判断加锁,改进如下:
static Singleton* GetInstance(){ if(p_obj == NULL){ lock(); if(p_obj == NULL){ p_obj = new Singleton(); cout << "New Singleton();" << endl; return p_obj; } unlock(); }}
多判断一次,减少多线程共同排队到这个位置的可能性。
- C++实现懒汉式单例模式
- [C#] 静态方式实现的单例是不是懒汉模式?
- 懒汉式单例模式(Singleton)
- 懒汉式单例设计模式
- 最佳懒汉式单例模式
- 单例设计模式(C#) 懒汉模式
- 懒汉式实现单例模式
- java实现单例模式--懒汉式
- 懒汉模式
- 饿汉式单例模式和懒汉式单例模式
- Java饿汉式单例模式和懒汉式单例模式
- 同步线程 懒汉式单例设计模式
- 由懒汉式单例模式谈懒加载
- 懒汉式单例模式的线程安全问题
- 懒汉式单例模式的多线程问题
- 多线程下的懒汉式单例模式
- 饿汉式与懒汉式单例模式的区别
- 懒汉式单例设计模式线程不安全
- ASP.NET Web Forms
- C#和.Ne学习第一天
- 求和:1+1/2-1/3+1/4-1/5……+1/n
- 小蓝酷骑接连倒闭,共享单车 15 亿押金有去无回
- 错账(dfs)
- C++实现懒汉式单例模式
- 数据库的优化
- 通过EasyBCD将Linux的启动菜单加入到Windows 的启动菜单
- 一个项目经理的个人体会、经验总结(新)
- 盒子端 CSS 动画性能提升研究
- kafka安装和启动
- tf.nn.softmax_cross_entropy_with_logits
- 测试用例方法及用例细节设计
- Docker中启动zookeeper