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

COM 智能指標實戰條款 13:必須提前釋放 COM 組件時,別妄想智能指標幫你完成

     編輯:關於C語言

條款 13:必須提前釋放 COM 組件時,別妄想智能指標幫你完成

陷阱 1:非空智能指標重新建立組件


void InSomewhere(IHello* pHello) {
    CComPtr spHello = pHello;
    spHello->DoSomething();
    hr = CoCreateInstance(CLSID_HELLO, NULL, CLSCTX_INPROC_SERVER,
                          IID_IHELLO, (void**)&spHello); // 危險:spHello 非空
    assert(SUCCEEDED(hr));
    spHello->DoOtherthing();
}

spHello 原有指向,取位址操作行為未定義:
• CComPtr:Debug 斷言,Release 靜默洩漏;
• _com_ptr_t:悄悄釋放原資源,無任何警告。

陷阱 2:成員函數版同樣失效


spHello.CoCreateInstance(CLSID_HELLO); // 仍只是 Debug 斷言,Release 洩漏

正確策略:手動提前釋放


void InSomewhere(IHello* pHello) {
    CComPtr spHello = pHello;
    spHello->DoSomething();
    spHello = NULL; // 或 spHello.Release() —— 手動提前釋放
    spHello.CoCreateInstance(CLSID_HELLO);
    assert(spHello);
    spHello->DoOtherthing();
}

陷阱 3:容器存儲智能指標的隱形洩漏


template
class MyStack {
    T* m_pArray; int m_nTop, m_nCapacity;
    void push(T Item) { m_pArray[m_nTop++] = Item; }
    T pop() { return m_pArray[--m_nTop]; } // 未清理原位置!
};

MyStack> g_myStack(1000);
void func() {
    for (int i=0; i<500; i++) {
        CComPtr sp = NULL;
        sp.CoCreateInstance(CLSID_CALCULATOR);
        g_myStack.push(sp); // 複製進容器,引用計數 +1
    }
    // ...
    for (int i=0; i<500; i++) {
        CComPtr sp = g_myStack.pop(); // 取出但容器原位置未清理
        sp->DoSomething();
    }
} // 容器後半部 500 個智能指標永不釋放 → 洩漏

原因:智能指標在全域空間,等待 ~MyStack() 需到程式結束。pop() 後容器仍持有引用,若後續元素不滿 500,後半部資源永不釋放。

修正:pop() 時清理原位置


T pop() {
    assert(m_nTop > 0);
    T temp = m_pArray[--m_nTop];
    m_pArray[m_nTop] = NULL; // 或 m_pArray[m_nTop].Release();
    return temp;
}

銘記:智能指標僅輔助管理記憶體,**必須提前釋放 COM 資源時,別妄想智能指標幫你完成**。

—— 作者:liuchang5 的專欄

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