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

COM 智能指標實戰條款 6:以智能指標全面取代介面指標,消除異常洩漏與類型不安全

     編輯:關於C語言

條款 6:盡量以智能指標替換介面指標

傳統手動管理引用計數代碼:


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

看似無問題,但若 OtherApp() 拋出異常,Release() 永不執行 → COM 組件無法釋放 → 資源洩漏。消除異常極難:第三方庫可能拋異常、C++ 預設操作(流、動態記憶體、dynamic_cast)可能拋異常。與其消滅異常副作用,不如用智能指標從根解決:


void SomeApp(IHello* pHello) {
    CComPtr spHello = pHello;
    OtherApp(); // 若拋異常,spHello 出作用域析構 → 自動 Release()
    spHello->Hello();
}

優勢:AddRef/Release 消失、邏輯清晰、異常安全(棧展開自動析構釋放)。

更強案例:消除冗餘引用計數操作

手動版:


IUnknown* pIUnknown = CreateInstance();
IX* pIX = NULL;
hr = pIUnknown->QueryInterface(IID_IX, (void**)&pIX);
if (SUCCEEDED(hr)) {
    pIX->Fx();              // 核心邏輯
    IX* pIX2 = pIX;         // 但引用計數操作佔一半代碼
    pIX2->AddRef();
    pIX2->Fx();
    pIX2->Release();
    pIX->Release();
}

因 pIX2 生命週期與 pIX 相同,實無需 AddRef/Release。智能指標版:


CComPtr spIX = NULL;
hr = spIX.CoCreateInstance(CLSID_MYCOMPONENT);
if (SUCCEEDED(hr)) {
    spIX->Fx();                    // 核心邏輯
    CComPtr spIX2 = spIX;      // 僅剩邏輯 :)
    spIX2->Fx();
}

極端案例:巢狀釋放地獄

手動版需層層 if (SUCCEEDED) 巢狀,Release 與 GetObject 成對,易漏、難讀、需拖捲軸:


void f() {
    IUnknown* rgpUnk[3];
    hr = GetObject(&rgpUnk[0]);
    if (SUCCEEDED(hr)) {
        hr = GetObject(&rgpUnk[1]);
        if (SUCCEEDED(hr)) {
            hr = GetObject(&rgpUnk[2]);
            if (SUCCEEDED(hr)) {
                UseObjects(rgpUnk[0], rgpUnk[1], rgpUnk[2]);
                rgpUnk[2]->Release();
            }
            rgpUnk[1]->Release();
        }
        rgpUnk[0]->Release();
    }
}

智能指標版:優雅扁平化:


void f() {
    CComPtr rgpUnk[3];
    if (FAILED(GetObject(&rgpUnk[0]))) return;
    if (FAILED(GetObject(&rgpUnk[1]))) return;
    if (FAILED(GetObject(&rgpUnk[2]))) return;
    UseObjects(rgpUnk[0], rgpUnk[1], rgpUnk[2]);
}

關鍵邏輯 UseObjects 一目瞭然。

類型安全:消除 IID 與指標型別錯配

手動 CoCreateInstance 易犯錯:IID_IY 配 IX*,void** 參數型別不安全。智能指標綁定 IID 與型別:


CComPtr spIX;
hr = spIX.CoCreateInstance(CLSID_MYCOMPONENT); // 無 IID、無 void**
spIX->fun();

_com_ptr_t 更進一步:建構函數直接建立組件:


_COM_SMARTPTR_TYPEDEF(ICalculator, __uuidof(ICalculator));
ICalculatorPtr spIX(CLSID_MYCOMPONENT);
spIX->fun();

除建立、斷言、調用外,零冗餘代碼。注意:智能指標提供「類型安全操作」,非「絕對類型安全」(詳見條款 13)。

—— 作者:liuchang5 的專欄

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