




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
C++设计模式第一讲第一页,共35页。
前言:
设计模式描述了对象如何进行通信才能不牵涉相互的数据模型和方法。
保持这种独立性一直是一个好的面向对象程序设计的目标。GangofFour的“DesignPatterns:ElementsofResualbelSoftware”书将设计模式归纳为三大类型,共23种。创建型模式:通常和对象的创建有关,涉及到对象实例化的方式。(共5种模式)行为型模式:通常和对象间通信有关。(共11种模式)结构型模式:描述的是如何组合类和对象以获得更大的结构。(共7种模式)
类模式描述的是如何使用继承提供更有用的程序接口。而对象模式描述的是如何通过使用对象组合或将对象包含在其他对象里,将对象组合成更大的一个结构。
2第二页,共35页。第一节:单例模式的适用范围1、单例模式可以保证:在一个应用程序中,一个类有且只有一个实例,并提供一个访问它的全局访问点。2、在程序设计过程中,有很多情况需要确保一个类只有一个实例。例如:windows系统中只能有一个窗口管理器某个程序中只能有一个日志输出系统一个GUI类库中,有且只有一个ImageManager还有其他无数种情况
3第三页,共35页。第二节:教课书中的标准实现
4第四页,共35页。第三节:教课书中的标准实现的优缺点
1、优点:该实现是一个"懒汉"单例模式,意味着只有在第一次调用GetInstance()静态方法的时候才进行内存分配。如果整个程序不调用该静态方法,则不会分配内存。相对应的是"饿汉"单例模式。2、缺点:1)"懒汉"模式虽然有优点,但是每次调用GetInstance()静态方法时,必须判断NULL==m_instance,使程序相对开销增大。2)由于使用指针动态内存分配,我们必须在程序结束时,手动的调用ReleaseInstance()静态方法,进行内存的释放。3)教科书标准实现最大的缺点是线程不安全。根据该模式的定义,整个应用程序中,不管是单线程,还是多线程,都只能有且只有该类的一个实例。而在多线程中会导致多个实例的产生,从而导致运行代码不正确以及内存的泄露。
5第五页,共35页。第三节:教课书中的标准实现的线程不安全性演示
6第六页,共35页。第三节:教课书中的标准实现的线程不安全性演示
71、我们创建3个辅助线程,外加main主线程,一共有4个线程。2、我们在每个辅助线程里面调用GetInstance()静态方法,由于每个线程回调函数速度非常快,导致每个线程在判断NULL==m_instance时,都返回true,从而导致每个线程回调函数都会创建一个CSingleton1对象并返回指向该对象的指针。3、我们根本没办法进行CSingleton1的内存释放,因为在多线程中,我们根本不知道是创建了1个、2个或3个CSingleton1的实例第七页,共35页。第四节:MeyersSingletonPattern实现
8第八页,共35页。第五节:MeyersSingletonPattern的优缺点
1、优点:1)该实现是一个"懒汉"单例模式,意味着只有在第一次调用GetInstance()时才会实例化。
2)不需要每次调用GetInstance()静态方法时,必须判断NULL==m_instance,效率相对高一些。3)使用对象而不是指针分配内存,因此自动回调用析构函数,不会导致内存泄露。4)在多线程下的确能够保证有且只有一个实例产生。
2、缺点:在多线程情况下,并不是真正意义上的线程安全的实现9第九页,共35页。第六节:MeyersSingletonPattern缺点演示10第十页,共35页。第六节:MeyersSingletonPattern缺点演示11第十一页,共35页。第六节:MeyersSingletonPattern缺点演示原因:这是因为C++中构造函数并不是线程安全的。C++中的构造函数简单来说分两步:第一步:内存分配第二步:初始化成员变量由于多线程的关系,可能当我们在分配内存好了以后,还没来得急初始化成员变量,就进行线程切换,另外一个线程拿到所有权后,由于内存已经分配了,但是变量初始化还没进行,因此打印成员变量的相关值会发生不一致现象。结论:Meyers方式虽然能确保在多线程中产生唯一的实例,但是不能确保成员变量的值是否正确.
12第十二页,共35页。第七节:线程安全的单例模式实现需求描述:1)是一个"懒汉"单例模式,按需内存分配。2)基于模板实现,具有很强的通用性。3)自动内存析构,不存在内存泄露问题(使用std::tr1::shared_ptr)。4)在多线程情况下,是线程安全的。5)尽可能的高效。(线程安全必定涉及到线程同步,线程同步分为内核级别和用户级别的同步对象,用户级别效率远高于内核级别的同步对象,而用户级别效率最高的是InterlockedXXXX系列API)。6)这个实际上也是一个Double-CheckedLocking实现的单例模式。是传统的Double-Checked-Locking变异版本。13第十三页,共35页。第八节:线程安全的单例模式实现(基础版)
14第十四页,共35页。第八节:线程安全的单例模式实现(基础版)
15第十五页,共35页。第八节:线程安全的单例模式实现(基础版)16第十六页,共35页。第九节:线程安全的单例模式(基础版)的测试17第十七页,共35页。第九节:线程安全的单例模式(基础版)的测试18第十八页,共35页。第十节:线程安全的单例模式(基础版)存在的不足
19单例的一个原则就是禁止构造函数和析构函数为public,防止外部实例化,仅允许调用GetInstance()等静态方法进行初始化。由于使用模板技术,如果我们不将基类和子类的构造和析构函数设置为public级别,模板实例化导致编译器报错。第十九页,共35页。第十一节:线程安全的单例模式(基础版)的修正
1、修正构造函数:1)将基类CSingletonPtr的构造函数为protected访问级别。
2)每一个继承自CSingletonPtr的子类也将构造函数声明为protected访问级别,并在继承类中声明友元类。
20第二十页,共35页。第十一节:线程安全的单例模式(基础版)的修正
1、修正构造函数:3)在上述代码设定以后,我们会发现对于构造函数,通过子类授权给基类的方式,我们能够很顺利的通过编译,代码正确的运行。这样我们解决了防止第三方调用Manager的构造函数,Manager类的构造函数只允许在GetInstance()静态方法中被调用。
21第二十一页,共35页。第十一节:线程安全的单例模式(基础版)的修正
2、修正析构函数:我们会发现,对于析构函数,它依旧是public访问级别的,为什么不让析构函数也声明为protected级别呢?因为由于我们使用了std::tr1::shared_ptr(与boost::shared_ptr基本一致),Manager类的析构委托给了shared_ptr,而Manager授权给的是其基类。所以如果我们将析构函数设置为protected级别,编译器会报错。那么我们第一个反应就是我们继续在Manager中授权shared_ptr。但是没成功。可能是由于shared_ptr实现的机制导致不能成功。难道我们真的没有办法将析构函数修正为受保护级别吗?山穷水尽疑无路,柳暗花明又一村!强大的shared_ptr删除器的出现解决了我们的问题!22第二十二页,共35页。第十一节:线程安全的单例模式(基础版)的修正
2、修正析构函数:1)在基类CSingletonPtr中声明并实现一个访问级别为private的嵌套类Deleter,代表一个删除器。重载函数调用操作符,该删除器类实际是一个仿函数对象。
图1、图2、2)在GetInstance()静态函数中增加删除器设置代码,见图2红色部分。一旦我们设置好删除器,那么在shared_ptr析构时不会直接调用delete而是调用删除器。这样我们就将子类T的析构函数隐藏起来,不被外部调用。23第二十三页,共35页。第十一节:线程安全的单例模式(基础版)的修正
2、修正析构函数:3)每一个继承自CSingletonPtr的子类也将构造函数声明为protected访问级别,但不需要声明授权友元类。通过上述步骤,我们将基类和子类的构造函数都声明为受保护级别,以防止外部调用。这样整个单例子类的生命周期都由shared_ptr控制。
24第二十四页,共35页。第十一节:线程安全的单例模式(基础版)的修正
3、修正GetInstance()静态方法:基础版的GetInstance()静态方法返回的是tr1::shared_ptr<T>结构,这样导致每次调用GetInstance()都会使shared_ptr的引用计数加1并调用shared_ptr的拷贝构造函数。在调用完成GetInstance()->Print方法后,又将临时产生的shared_ptr对象引用计数减1,这样对效率有非常大的影响。我们要避免这种情况,那么我们要做的是修改代码,直接在GetInstance()中返回T的引用。
25第二十五页,共35页。第十一节:线程安全的单例模式(基础版)的修正
3、修正GetInstance()静态方法:更进一步,我们使用编译器提供的本质函数。
26第二十六页,共35页。第十二节:线程安全的单例模式(修正版)的优缺点1、优点:该实现是一个"懒汉"单例模式,意味着只有在第一次调用GetInstance()静态方法的时候才进行内存分配。通过模板和继承方式,获得了足够通用的能力。在创建单例实例的时候,具有线程安全性。通过智能指针方式,防止内存泄露。具有相对的高效性。2、缺点:肯定没有单线程版本的效率高。每个子类必须要授权基类,我们可以写一个宏减少输入:#defineDECLARE_SINGLETON_CLASS(type)\friendclassCSingletonPtr<type>;
27第二十七页,共35页。第十三节:饿汉类型单例模式实现饿汉模式意味着在主线程(main函数代表主线程)之前就对类进行内存分配和初始化。实现代码如下:
28第二十八页,共35页。第十四节:饿汉类型单例模式测试
29第二十九页,共35页。第十四节:饿汉类型单例模式测试
30第三十页,共35页。第十五节:饿汉类型单例模式最隐晦的问题
ScottMeyers在其《EffectiveC++》第三版中的04条款:确定对象在使用前先被初始化有关Non-LocalStatic变量初始化顺序的描述中举例子说明该模式的缺陷。1、Non-LocalStatic变量的确在主线程之前进行初始化。2、但C++标准对于不同的编译单元内的Non-Local-Static对象的初始化相对次序并无明确定义。这是有原因的:决定他们的初始化顺序相当困难,根本无解。(.cpp文件编译后形成.Obj文件,代表一个编译单元)。3、上述现象主要体现在:如果某一个编译单元内的某个Non-Local-Static对象的初始化使用了另一个编译单元内的某个Non-Local-Static对象,它所用到的对象可能尚未被初始化因此ScottMeyers提出了我们第三节中实现的单例模式,我们发现在多线程下还是存在问题。关于这个隐晦的问题,在我们现在测试代码中很难重现,但是网上确实有很多文章在实际项目中遇到这个问题。31第三十一页,共35页。第十六节:单例模式四种实现总结
从编译器以及是否线程安全方面考虑:
1、如果你使用vc6编译器,请放弃设计模式。2、如果你整个程序是单线程的,那么标准模式或Meyers单例模式是你最佳选择。3、如果你使用符合C++0X标准的编译器的话,由于C++0X标准规定:要求编译器保证内部静态变量的线程安全性。(vc2010及以上版本。因此Meyers单例模式是你最佳选择。4、如果你使用VC6以后,vc2010以下版本的编译器的话,并且需要线程安全,则使用第四节实现的Double-Checked-Locking版本的单件模式。5、尽量避免使用饿汉单例模式,因为具有潜在,不可预测的风险。32第三十二页,共35页。第十七节:单例模式实现的固定格式总结
从单例模式实现的角度考虑:
1、总是避免第三方调用拷贝构造函数以及赋值操作符2、总是避免第三方调用构造函数3、尽量避免第三方调用析构函数4、总是需要一个静态方法用于全局访问
33第三十三页,
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024-2025学年高中物理课时分层作业11磁性材料含解析新人教版选修1-1
- 园区污水处理厂(一期)及配套管网工程环境影响报告书【模板】
- 中国海南省木制品市场全面调研及行业投资潜力预测报告
- 绿色建筑设计阶段预评价报告
- 2025年吡虫啉泡腾片剂项目投资可行性研究分析报告
- 陕西民用无人机项目投资分析报告模板范本
- 2025年中国无线AP网络设备行业市场发展前景及发展趋势与投资战略研究报告
- 2025年扶梯侧板项目可行性研究报告
- 中国观赏鱼饲料市场深度调研分析及投资前景研究预测报告
- 2025年象鼻子刀行业深度研究分析报告-20241226-191513
- 部编人教版语文小学六年级下册第四单元主讲教材解读(集体备课)
- (2024年)师德师风学习内容教师师德师风培训内容通用多篇
- GB/T 3452.3-2005液压气动用O形橡胶密封圈沟槽尺寸
- EN779-2012一般通风过滤器——过滤性能测定(中文版)
- 形位公差测量方法
- 车辙防治指导意见(确定稿)
- 一个近乎完美的微信引流招生方案
- 门诊特殊病种审批表
- T_CEC 102.1-2016 电动汽车充换电服务信息交换 第1部分_总则_(高清-最新版)
- 国际形式发票模板
- 山西省会计师事务所服务收费标准(汇编)
评论
0/150
提交评论