有效的使用和设计COM智能指针 条款8:条款9:尽可能不将智能指针放置于堆上
来源:互联网 发布:mac双系统分区比例 编辑:程序博客网 时间:2024/05/11 12:41
条款8:对智能指针的使用规则烂熟于心
我们在第一章的时候接触到了普通接口引用计数的规则(条款2)。那么在开始这一章节之前,我们来看一下使用智能指针要遵循哪些规则。智能指针的使用规则相对于接口指针会更加复杂,但考虑到他所提供的便利以及安全性。或许谨记这些规则是值得的:
1.资源申请之时将其立即捆绑到一个智能指针之上(RAII)。详见条款1。
2.函数返回一个接口指针之前,调用Dettach()及时将智能指针与接口指针解绑定。详见条款12。
3.智能指针需使用Attach()函数接收来自某一函数返回值中的接口指针。详见条款12。
4.利用传出参数传出接口指针时,需要保证传入的智能指针为空。详见条款25。
条款9:尽可能不将智能指针放置于堆上
先来看一段哭笑不得的代码:
void SomeApp(){ CComPtr<ICalculator>* pspMyCalculator = new CComPtr<ICalculator>; (*pspMyCalculator).CoCreateInstance(CLSID_CALCULATOR); pspMyCalculator->DoSomething(); delete pspMyCalculator;}
我担保你不会写出像上面那样的代码,原因是他将“智能”这顶桂冠从智能指针头上又摘了下来。当然,赋值运算符重载中仍将调用AddRef,智能指针也仍旧给我们提供类型安全的特性。但异常安全,自动释放引用计数,已经离我们远去。想想DoSomething()抛出一个异常,会发生什么?资源泄漏了……
或许你说你永远不会傻到写出上面这样的代码来。然后,类似的悲剧还是发生了,只不过它更加隐晦:
class MyClass{public: MyClass(); ~MyClass(); DoSomething();private: CComPtr<ICalculator> m_spCalculator;};
这个声明没有问题,但是下面的使用方式却带来了一个潜在问题。
void SomeApp(){MyClass* pMyClass = new MyClass(); // 哦~ 果然还是出问题了。...delete pMyClass;}
试想一下上面代码会发生什么,情况不容乐观。智能指针出栈的条件是delete pMyClass。但如果他永远无法执行到呢?内存泄漏又发生了。
或许你会说这种问题还是太过于明显,但我的举例只是让你明白问题的所在。在正真的代码中MyClass可能有是另外一个堆上对象的成员属性,而这个堆上对象的申请过程可能在一个Init()函数中,释放过程却在UnInit()函数中,这中间相差十万八千里。要发现他是多么的困难。
因此忠告是“尽可能不将智能指针放置于堆上”,对于堆上出现的智能指针一定要严格提防。但是你可能还有最后一个疑惑:为什么是“尽可能”而不是“切勿”?难道某些时候我们还是需要堆上的智能指针吗?
答案是肯定的,我们需要堆上的智能指针。你可能会问,如果我们确实需要一个在堆上的资源,那应该如何做呢?
一种特殊情况是资源的生命周期与程序进程相同,因此而不存在提前释放资源的难题,如下这种做法。那它是安全的:
class TheApp{public: TheApp(); ~TheApp(); DoSomething();private: CComPtr<IDocument> m_spDocument; //这个接口在整个程序生命周期中使用};TheApp g_theApp; //全局对象会在堆上开辟空间。TheApp *g_pTheApp = NULL; //或者采用这种方式,在另一个地方new出来。
若的生命周期是全局的,那就将其放置到堆上不会出现太多问题。毕竟他可能需要在程序结束之后才释放。但若他的生命周期并非全局,而又需要动态申请的情况呢?
正确的做法是再用一个资源管理对象或智能指针对象负责此堆上的资源。他大概会像如像这样:
class TheApp //若TheApp需要最堆上申请{public: TheApp(); ~TheApp(); DoSomething();private: CComPtr<IDocument> m_spDocument; //一个会出现在堆中的智能指针};auto_ptr<TheApp> func(){ auto_ptr<TheApp> spTheApp(new TheApp); //用另一个智能指针负责堆上资源。 ... return spTheApp; //将其传递出去,以延续堆上对象的生命周期}
请记住“尽可能不将智能指针放置于堆上”。OK,结束了~
- 有效的使用和设计COM智能指针 条款8:条款9:尽可能不将智能指针放置于堆上
- 有效的使用和设计COM智能指针——条款21:巧妙的将对象伪装成指针
- 有效的使用和设计COM智能指针——条款6:尽量以智能指针替换接口指针
- 有效的使用和设计COM智能指针——条款14:有意识的限制智能指针的生命周期
- 有效的使用和设计COM智能指针——条款18:重载运算符不应当扭曲其语义
- 有效的使用和设计COM智能指针——条款1:智能指针之前世今生
- 有效的使用和设计COM智能指针——条款10:尽量减少智能指针和接口指针的混用
- 有效的使用和设计COM智能指针 ——条款5:了解_com_ptr_t 设计背后的历史原因
- 有效的使用和设计COM智能指针 ——条款16:智能指针的引入不能违反COM引用计数规则
- 有效的使用和设计COM智能指针 ——条款13:必须提前释放COM组件时,别妄想智能指针帮你完成
- 有效的使用和设计COM智能指针——条款2:引用计数的是与非
- 有效的使用和设计COM智能指针——条款4:理解ATL的CComPtr提倡简单,高效
- 有效的使用和设计COM智能指针——条款15:以原则中的优先级作为取舍的依据
- 有效的使用和设计COM智能指针—条款4:理解ATL的CComPtr提倡简单
- 有效的使用和设计COM智能指针——条款23:为例外条件准备应对策略。
- 有效的使用和设计COM智能指针——条款3:按照功能和实现原理选择合适的智能指针
- 有效的使用和设计COM智能指针——条款22:果断放弃二进制重用,而采用模版编写智能指针
- 有效的使用和设计COM智能指针——条款27:考虑__uuidof与uuid在关键字在不同编译器上的兼容问题
- Web Dynpro for ABAP 之 Web Dynpro Window& Web Dynpro Application
- MCU屏FMARK信号的作用
- 局域网文件,批量、定时、单文件传输工具。
- wap 长短地址转换
- 概念
- 有效的使用和设计COM智能指针 条款8:条款9:尽可能不将智能指针放置于堆上
- ubuntu 10.10 桌面版关闭图形界面的方法
- SQL查询一个月第一天/最后一天
- xml pp2
- php: 判断今日是本月的第几个星期几
- MyEclipse 快捷键
- 有效的使用和设计COM智能指针——条款10:尽量减少智能指针和接口指针的混用
- SVN Server Windows 下部署
- JAVA网络编程