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

COM 智能指標實戰條款 10:嚴禁智能指標與介面指標混用,參數與返回值除外

     編輯:關於C語言

條款 10:盡量減少智能指標與介面指標混用

混用導致的資源洩漏陷阱


void func() {
    ICalculator* pCalculator = NULL;
    CComPtr spCalculator = NULL;
    hr = CoCreateInstance(CLSID_CALCULATOR, NULL, CLSCTX_INPROC_SERVER,
                          IID_ICALCULATOR, (void**)&pCalculator); // AddRef 一次
    assert(hr);
    spCalculator = pCalculator; // 賦值運算子再 AddRef 一次
    spCalculator->DoSomething();
} // 析構只 Release 一次 → 計數不歸零 → 洩漏

問題核心:CoCreateInstance 呼叫 AddRef,賦值給智能指標再 AddRef,析構僅 Release 一次 → 引用計數不歸零,組件游離記憶體。

補 pCalculator->Release() 雖可修復,但違背引入智能指標簡化開發的初衷,需花更多心力思考引用計數。

最佳解法:徹底淘汰函數內介面指標


void func() {
    CComPtr spCalculator = NULL; // 只有智能指標
    hr = spCalculator.CoCreateInstance(CLSID_CALCULATOR); // 引用計數 = 1
    assert(hr);
    spCalculator->DoSomething();
} // Release 後計數歸零,正確釋放

例外:函數參數與返回值保留介面指標


void SomeApp(IHello* pHello) { // 參數用介面指標
    CComPtr pCopy = pHello;
    OtherApp();
    pCopy->Hello();
}

四大理由:

  1. 智能指標無法在 IDL 描述;
  2. 增加介面複雜度,理解困難;
  3. 第三方智能指標需隨介面發布,用戶無實現則無法使用;
  4. 傳遞開銷大,降低效能。

返回值用智能指標的災難性後果


CComPtr GetView(int nIndex) {
    CComPtr spView = NULL;
    spView.CreateInstance(CLSID_MYCOMPONENT);
    return spView; // 返回臨時物件,引用計數 = 1
}

// 調用端
IView* pIView = NULL;
pIView = GetView(); // 臨時物件賦值後析構 → Release → 計數歸零 → 組件被釋放
pIView->DoSomething(); // 崩潰!

結論:混用導致引用計數難以琢磨,函數內部徹底禁用介面指標;參數傳遞與返回值允許介面指標存在。

—— 作者:liuchang5 的專欄

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