2013-11-15 40 views
3

我最近看到的智能指針和他們的陷阱一個PowerPoint,它有這個幻燈片(幾乎沒有評論或解釋:此智能指針使用有什麼問題?

在背景:特別是_com_ptr_t,智能指針的COM接口,處理的AddRef /釋放如由_COM_SMARTPTR_TYPEDEF宏創建*


錯誤:

IObjectPtr spObj; 
for (int i(0); i<MAX; i++) 
{ 
    //passed as actual , no release of previous ptr value 
    spOtherObj->get_Obj(&spObj); 
} 

下一張幻燈片聲稱,它是好的,如果你把spObj循環的範圍內:


右:

for (int i(0); i<MAX; i++) 
{ 
    IObjectPtr spObj; 
    //passed as actual , no release of previous ptr value 
    spOtherObj->get_Obj(&spObj); 
} 

我研究這個,仍然無法弄清楚他們在說什麼。
第一個問題與第二個問題解決了什麼問題?


我猜,在更全面的背景下,正確/錯誤代碼是這樣:
雖然我可能是錯誤的,我的假設

_COM_SMARTPTR_TYPEDEF(ICalendar, __uuidof(ICalendar)) 

void get_Calendar(ICalendarPtr* pCalendar) 
{ 
    *pCalendar.CreateInstance(__uuidof(Calendar));   
} 

void WrongMethod(void) 
{ 
    ICalendarPtr spCalendar; 
    for (int i(0); i<MAX; i++) 
    { 
     //passed as actual , no release of previous ptr value 
     get_Calendar(&spCalendar); 
    } 
} 
+1

它也沒有幫助,沒有上下文來說明get_Obj是在做什麼。 –

+0

指針始終是智能的;) – lordkain

+1

這是關於COM對象的[_com_ptr_t](http://msdn.microsoft.com/en-us/library/vstudio/417w8b3b.aspx)智能指針的上下文。 – abelenky

回答

7

這最有可能是指ATL::CComPtr而不是_com_ptr_t

問題是,CComPtr::operator&返回被包裝的指針的地址,但不釋放它,因此如果它被聲明在循環之外,假定被包裝的接口不是NULL,則泄漏對象。

實施承認這個事實,這是從ATL頭文件,包括註釋直接複製:

//The assert on operator& usually indicates a bug. If this is really 
//what is needed, however, take the address of the p member explicitly. 
T** operator&() throw() 
{ 
    ATLASSERT(p==NULL); 
    return &p; 
} 

_com_ptr_t修復了這個問題,並且一般使用起來更加方便,所以應該首選是適用的。

+0

非常好的答案。如果你是對的,難怪我無法弄清楚。我一直在看'_com_ptr_t',它沒有這個問題! – abelenky

+0

實際上,我完全忘記了CComPtr的這個問題,直到我看到你的問題:) –

+0

我不記得CComPtr是否仍然支持它或者,但它*使用*有一個調試模式來檢測'operator& '如果在非空實例上觸發則會拋出一個斷言。不知道它是否仍然存在。 – WhozCraig

6

這些是ATL :: CComPtr智能指針(這些指針稍微聰明,順便說一句)。

該對象類型的operator &返回其中的原始接口指針的地址。因此,第一個循環實際上並沒有比這樣做更好:

IObject* pObj = NULL; 
for (int i(0); i<MAX; i++) 
{ 
    spOtherObj->get_Obj(&pObj); 
} 

每次迭代都不會釋放先前迭代的接口。它只是丟失,泄漏,並且底層coclass上的引用計數將被人爲地鎖定。

通過移動智能指針內循環,你現在讓析構函數的智能指針對象清理獲取的每個接口的,發射->Release(),下一次迭代之前。擴展後的代碼實際上是這樣的:

for (int i(0); i<MAX; i++) 
{ 
    IObject* pObj = NULL; 
    spOtherObj->get_Obj(&pObj); 
    if (pObj) pObj->Release(); 
}