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();
}
四大理由:
CComPtr GetView(int nIndex) {
CComPtr spView = NULL;
spView.CreateInstance(CLSID_MYCOMPONENT);
return spView; // 返回臨時物件,引用計數 = 1
}
// 調用端
IView* pIView = NULL;
pIView = GetView(); // 臨時物件賦值後析構 → Release → 計數歸零 → 組件被釋放
pIView->DoSomething(); // 崩潰!
結論:混用導致引用計數難以琢磨,函數內部徹底禁用介面指標;參數傳遞與返回值允許介面指標存在。
—— 作者:liuchang5 的專欄