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

COM 智能指標實戰條款 8-9:使用規則爛熟於心,堅決拒絕堆上智能指標陷阱

     編輯:關於C語言

條款 8:對智能指標使用規則爛熟於心

智能指標使用規則較介面指標更複雜,但為便利與安全值得謹記:

  1. RAII 原則:資源申請即綁定智能指標(詳條款 1);
  2. 返回前 Detach():函數返回介面指標前,用 Detach() 解除綁定(詳條款 12);
  3. 接收返回值用 Attach():接收函數返回的介面指標需用 Attach()(詳條款 12);
  4. 傳出參數必為空:利用傳出參數傳遞介面指標時,輸入的智能指標必須為空(詳條款 25)。

條款 9:盡可能不將智能指標放置於堆上

反面教材:顯式 new 智能指標


void SomeApp() {
    CComPtr* pspMyCalculator = new CComPtr;
    (*pspMyCalculator).CoCreateInstance(CLSID_CALCULATOR);
    pspMyCalculator->DoSomething();
    delete pspMyCalculator; // 若 DoSomething 拋異常 → 洩漏
}

智能指標上堆 = 摘掉「智能」桂冠。賦值仍呼叫 AddRef、仍有類型安全,但異常安全、自動釋放蕩然無存。

隱形殺手:類成員智能指標 + 類實例上堆


class MyClass {
    CComPtr m_spCalculator;
};
void SomeApp() {
    MyClass* pMyClass = new MyClass(); // 智能指標間接上堆
    delete pMyClass; // 若無法執行 → 洩漏
}

真實場景中 MyClass 可能是另一堆上物件的成員,申請在 Init()、釋放在 UnInit(),中間相隔十萬八千里,極難發現。

為何「盡可能」而非「切勿」?

特殊情況:資源生命週期 = 程序進程生命週期(全域物件),無提前釋放問題:


class TheApp {
    CComPtr m_spDocument; // 全程使用
};
TheApp g_theApp; // 全域物件(堆上)
// 或
TheApp* g_pTheApp = new TheApp(); // 動態建立但全程存活

正確做法:雙層資源管理

若確需堆上資源且生命週期非全域,再用一個資源管理物件/智能指標負責該堆上物件:


class TheApp {
    CComPtr m_spDocument; // 會出現在堆中的智能指標
};
auto_ptr func() {
    auto_ptr spTheApp(new TheApp); // 外層智能指標管理堆上 TheApp
    return spTheApp; // 傳遞出去延續生命週期
}

銘記:盡可能不將智能指標放置於堆上,堆上智能指標必須嚴格提防!

—— 作者:liuchang5 的專欄

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