首页 智能指针attach和detach

智能指针attach和detach

举报
开通vip

智能指针attach和detach引用计数我不怕之智能指针 2009-11-06 21:55:23| 分类: 默认分类 |字号 前言 使用引记数,就算是再历害的高手也难免会出错。而一但出错了,之后再去查问题可就相当的困难了。正如我曾经看到,有一段代码是这样的: m_spView->Release(); m_spView->Release(); m_spView->Release(); 看 到这段代码,就知道引用计数出问题了。他想通过这种方式,把多出来的计数Release掉。但这么做能解决问题吗?答案是不能,这样的代码还可能造成严重...

智能指针attach和detach
引用计数我不怕之智能指针 2009-11-06 21:55:23| 分类: 默认分类 |字号 前言 使用引记数,就算是再历害的高手也难免会出错。而一但出错了,之后再去查问题可就相当的困难了。正如我曾经看到,有一段代码是这样的: m_spView->Release(); m_spView->Release(); m_spView->Release(); 看 到这段代码,就知道引用计数出问题了。他想通过这种方式,把多出来的计数Release掉。但这么做能解决问题吗? 答案 八年级地理上册填图题岩土工程勘察试题省略号的作用及举例应急救援安全知识车间5s试题及答案 是不能,这样的代码还可能造成严重 的稳定性问题。解决引用计数问题,除了要了解引用计数规则外,我们还提昌要用智能指针。智能能帮助我们很好的处理引用计数问题。 智能指针的差异 在用VC开发应用程序时,有两个引用计数类可供我们使用。_com_ptr_t与CComPtr,它们都能很好的帮助我们解决引用计数处理。但这两个类还是有一点小小的区别,有的时候这一点区别也是致命的,因此我们必须清楚它们的差别。下面我罗列了它们之间的差别: 1. CComPtr的&运算符不会释放原指针,而_com_ptr_t会释放原指针。 2. CComPtr对AddRef与Release做了限制,也就是不充许调用这两个方法,而_com_ptr_t并没有限制。 3. CComPtr只能接受模版参数指定的指针,_com_ptr_t可以接受任何接口指针,并自动调用QueryInterface得到 模板 个人简介word模板免费下载关于员工迟到处罚通告模板康奈尔office模板下载康奈尔 笔记本 模板 下载软件方案模板免费下载 参数指定的指针类型。 这些区别,导致了有些代码不能同时应用于两个智能指针。 &运算符差异带来的风险 HRESULT hr GetView(int i, /*out*/IView** ppView) { *ppView = m_Views[i]; (*ppView)->AddRef(); return S_OK; } CComPtr spView; for (int i = 0; i < 10; i++) { GetView(i, &spView); spView->… } 以 上代码会导致引用计数出错,前面的9个View的引用计数并没有Release。CComPtr的&运算符,会返回 IView**也就是CComPtr内部成员的地址,但它不释放原来的指针。而GetView又会修改指针,直接把原来的指针抛弃了。 这个代码可以这样改: for (int i = 0; i < 10; i++) { CComPtr spView; GetView(i, &spView); spView->… } 把指针作为循环的局部变量,这样每次循环退出前spView都会被析构,最终调用Release。当然还能这样改: COM_SMARTPTR_TYPEDEF(IView, __uuidof(IView)); IView Ptr spView; for (int i = 0; i < 10; i++) { GetView(i, &spView); spView->… } _com_ptr_t的&运算符会帮助我们把原来的指针Release掉,所以我们就不必担心引用计数没有释放。 禁用AddRef与Release 然我们使用的智能指针,就不要再去调AddRef或Release了。如果再去手工调用它们,就失去了智能指针的好处。CComPtr有一个非常巧妙的方法,禁止调用这两个方法。它声明了一个类_NoAddRefReleaseOnCComPtr,它的定义如下: template class _NoAddRefReleaseOnCComPtr : public T { private: STDMETHOD_(ULONG, AddRef)()=0; STDMETHOD_(ULONG, Release)()=0; }; 我们看到,里面就定义了两个私有函数。AddRef与Release,它们重写了IUnknown的这两个方法,并且继承自模板T。再来看段代码: _NoAddRefReleaseOnCComPtr* operator->() const throw() { ATLASSERT(p!=NULL); return (_NoAddRefReleaseOnCComPtr*)p; } 我 们看到的是CComPtr的“->”运算符,它将内部的指针强制转换成_NoAddRefReleaseOnCComPtr*。 其中T是CComPtr的模板参数,也就是接口指针类型。可以看出_NoAddRefReleaseOnCComPtr继承自接口类 型,因此通过_NoAddRefReleaseOnCComPtr*可以调用T的所有函数。前面我们看到 NoAddRefReleaseOnCComPtr的两个私用函数,AddRef与Release,如果有谁想调用就会报编译错误。 自动QueryInterface _com_ptr_t有多个=运算符版本,代码如下: template class _com_ptr_t { public: typedef _IIID ThisIIID; typedef typename _IIID::Interface Interface; // Queries for interface. template _com_ptr_t& operator=(_InterfaceType* p) { HRESULT hr = _QueryInterface(p); if (FAILED(hr) && (hr != E_NOINTERFACE)) { _com_issue_error(hr); } return *this; } // Saves the interface. template<> _com_ptr_t& operator=(Interface* pInterface) throw() { if (m_pInterface != pInterface) { Interface* pOldInterface = m_pInterface; m_pInterface = pInterface; _AddRef(); if (pOldInterface != NULL) { pOldInterface->Release(); } } return *this; } 其中 template _com_ptr_t& operator=(_InterfaceType* p)是一个模板函数,接受任意类型的指针,函数内部会调用传入参数“p”的QueryInterface。 template<> _com_ptr_t& operator=(Interface* pInterface) throw()是模板函数的一个偏特化版本,接受_com_ptr_t模板参数中指定的指针类型。当传入的接口指针类型,与类模板指定的类型一样时这个函 数会被调用。它不需要做QueryInterface的调用,只是简单的AddRef; 综上所述,两个智能指针在同一份代码里混用,很可能导致不良后果。所以我认为,最好不要在同一份代码里混用。而这两个指针,我很喜欢_com_ptr_t,它在许多方面明显优于CComPtr。 Attach与Detach 使用了智能指针,也并不是高枕无忧了。它还是给我们带来了一些新的问题。 有一些第三方类库设计的不合理,它在函数的返回值里返回接口指针。如下代码就导会导致引用计数泄漏: IView* GetView(int nIndex) { IView* pView = m_Views[nIndex]; pView->AddRef(); return pView; } IViewPtr spView = GetView(0); 以上代码,注意调用GetView的地方。IViewPtr是智能指针,它的=运算符是会再调用AddRef而GetView里已经调了一次AddRef了,这里多了一次AddRef。别问我GetView中为什么要AddRef,这是引用计数规则,不清楚请看 HYPERLINK "http://chen1996.blog.163.com/blog/static/44410052200910695425230/"《引用计数我不怕之引用计数规则》 HYPERLINK "http://引用计数我不怕之引用计数规则/"。 解决这个问题的方法就是用Attach函数 IViewPtr spView; spView. Attach(GetView(0)); 也许是有人写了Attach,而其它人不明白Attach的意思,结果写出了这样的代码。 void SetView(IView* pView) { m_spView.Attach(pView); } 根据引用计数规则,将指针保存为副本,必须AddRef。但是这个例子里没有这么干,结果m_spView变成了野指针。 前面我们看到的GetView很简单,但是下面我们要做一别的事情,于是要用智能指针。 HRESULT hr GetView(int nIndex, IView** ppView) { IViewPtr spView = m_Views[nIndex]; if (spView->IsVisable() != S_OK) return E_FAILD; *ppView = spView; return S_OK; } 关于同志近三年现实表现材料材料类招标技术评分表图表与交易pdf视力表打印pdf用图表说话 pdf 面看来没什么问题,但在函数返回后,智能指针又会调用一次Release。要解决这个问题,可以调用Detach。 HRESULT hr GetView(int nIndex, IView** ppView) { IViewPtr spView = m_Views[nIndex]; if (spView->IsVisable() != S_OK) return E_FAILD; *ppView = spView. Detach(); return S_OK; } Detach还是会被乱用,看到这样的代码还真是哭笑不得。 HRESULT hr ChangeView(int nIndex) { IViewPtr spView = m_Views[nIndex].Detach(); spView->Change(); return S_OK; } 这段代码能导致两个问题 1. 引用计数泄漏 2. m_Views中的指针变成空了 泄漏是由于Detach返回IView*,并不会Release,而spView又会再调用一次AddRef。智能指针的Detach是会把自己设成空的,否则还叫什么Detach。 使用智能指针,是解决引用计数问题最好的办法。不要因为用智能指针,会引入新的问题,而放弃使用它。只要花心思搞清楚智能指针的不同点,使用时注意一些细节问题,使用起来应该会变的非常轻松。
本文档为【智能指针attach和detach】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_434321
暂无简介~
格式:doc
大小:29KB
软件:Word
页数:5
分类:互联网
上传时间:2013-08-08
浏览量:28