首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

COM 引用計數的生與死:手動管理的三大鐵律與智能指標的半自動化救贖

     編輯:關於C語言

條款 2:引用計數的是與非

使用 COM 開發的程式設計師,常被介面引用計數問題搞得頭破血流。問題根源簡單:客戶端僅知組件介面,不知兩個介面是否指向同一組件,故無法直接釋放組件,導致組件生命週期無法由客戶端便利控制。

為解此困境,COM 採用引用計數:組件依計數值決定何時釋放資源。客戶端查詢介面時計數 +1,用完呼叫 Release() 計數 -1,計數歸零時組件自行從記憶體刪除。

三條簡單卻殘酷的鐵律

引用計數雖合理,但嚴格要求開發者遵循三條規則:

  1. 返回前呼叫 AddRef():返回介面指標的函數(QueryInterface、CreateInstance 等)需在返回前呼叫 AddRef(),使客戶端無需再呼叫。
  2. 使用完呼叫 Release():用完介面後必須呼叫其 Release()。
  3. 賦值後呼叫 AddRef():將一個介面指標賦值給另一個時,需呼叫 AddRef(),即建立新引用時增加計數。

依此編寫的程式碼如下:

void SomeApp(IHello* pHello) {
    IHello* pCopy = pHello;
    pCopy->AddRef();           // 規則 3
    OtherApp();
    pCopy->Hello();
    pCopy->Release();          // 規則 2
}

三條規則看似簡單,但程式設計師若在某時刻遺漏任一規則,引用計數即陷入混亂。樂觀情況下程式因存取已釋放資源而崩潰;運氣不好時,資源洩漏悄無聲息發生。引用計數雖讓組件生命週期自管,卻使 COM 使用變得極度危險——每個使用者都必須嚴格正確呼叫 AddRef()/Release(),一旦出錯,輕則物件無法釋放,重則重複刪除導致崩潰。

智能指標的半自動化救贖

以 CComPtr 為例改寫上述程式碼:

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

AddRef() 與 Release() 操作消失,程式碼大幅精簡,更重要的是帶來更多便利(後續條款詳細討論)。之所以說是「半自動化」,因為部分場合仍需手動管理引用計數。

—— 作者:liuchang5 的專欄

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved