智能指標使用規則較介面指標更複雜,但為便利與安全值得謹記:
Detach() 解除綁定(詳條款 12);Attach()(詳條款 12);
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 的專欄