有效的使用和設計COM智能指針——條款2:引用計數的是與非

 

條款2引用計數的是與非

更多條款請前往原文出處:http://blog.csdn.net/liuchang5

使用COM做開發的程序員往往會被接口引用計數所帶來的問題搞得頭破血流。引用計數這個老大難問題存在的原因也相當簡單:在COM開發中,客戶僅僅知道組件的接口。當使用完一個接口而要使用另外一個接口時,由於客戶並不知道兩個接口是否指向同一組件,因此客戶無法直接將組件釋放。COM組件的生命週期也因此無法被客戶方便的控制。

於是爲了解決這一問題,COM組建使用了引用計數。每個組件根據引用計數的數值決定何時釋放自身所佔用的資源。當客戶從某個組件查詢出一個接口時,此引用計數值將增1。當客戶使用完此接口時,此引用值減1。如果某個組件的引用計數值降至0時候,組件則會將自己從內存中刪除。

通過引用計數確實可以很合理的管理組件的生命週期,但也嚴格要求開發人員遵循下面這三條簡單規則【1

1.在返回之前調用AddRef。對於那些返回接口指針的函數,在返回前應用相應的指針調用AddRef。這些函數包括QueryInterfaceCreateInstance。這樣當客戶從這種函數得到一個接口後,他將無需調用AddRef

2.使用完接口之後調用Release。在使用完某個接口之後應調用此接口的Release函數。

3.在賦值之後調用AddRef。將一個接口指針賦值給另外一個接口指針時,應調用AddRef。換句話說,在建立接口的另外一個引用之後應增加相應組件的引用計數。

根據如上三條原則我們需要編寫出了形如下例的代碼:

void SomeApp( IHello * pHello )
{

    IHello* pCopy = pHello;
    pCopy->AddRef(); 
    OtherApp();
    pCopy->Hello();
    pCopy->Release();
}


這三條規則看似簡單,但是程序員若在某一時刻遺漏掉其中的某條規則,則會使得引用計數陷入混亂。出錯後,最樂觀的情況是程序由於訪問了已經被釋放的資源,而直接崩潰。如果運氣不是特別好,那麼資源泄露則悄無聲息的發生了。

可以看出由於引用計數的引入,COM組件的生命週期可以自行管理,但同時也使得COM的使用變得非常危險。因爲使用過程中需要每一個使用者都要嚴格並且正確的調用AddRef()和Release(),一旦出現問題,就會造成對象不能被正常釋放,或者對象被重複刪除,造成程序崩潰。所以使用COM接口,必須小心翼翼纔行。

我們試着用智能指針改寫上述代碼。這裏以CComPtr爲例,更多關於它的介紹我們放到後續條款中。上述函數將會變成如下這種形式:

void SomeApp( IHello * pHello )
{
    CComPtr<IHello> spHello= pHello;
    OtherApp();
    spHello->Hello();
} 


智能指針給我帶來了引用計數的半自動化處理(之所一說是半自動化,是因爲有些地方仍然需要手動管理引用計數)。AddRef()和Release()操作不見了,代碼簡潔了不少,而更重要的是它還將帶來更多的便利條件。我們在之後的條款中會進一步討論。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章