軟體必然出錯:邏輯錯誤、資源耗盡、使用者操作失誤、外部環境變化。C++ `try`/`catch`/`throw` 機制配合 MFC 例外類別 (`CException`、`CMemoryException`、`CFileException` 等),提供結構化錯誤處理。本文對比傳統錯誤碼與例外處理,示範標準與 MFC 例外捕捉模式,並說明資源清理 (RAII) 關鍵。
// 傳統:每層檢查返回值
BOOL ReadData() {
FILE* f = fopen("data.dat", "r");
if (!f) return FALSE;
if (fread(buf, 1, 1024, f) != 1024) { fclose(f); return FALSE; }
fclose(f); return TRUE;
}
void PrintData() { for (int i=0;i<1024;i++) printf("%x ", buf[i]); } // 隱患:buf 可能 NULL
呼叫端若忘記檢查 `ReadData()` 返回值,`PrintData()` 存取野指標 → 崩潰。
void ReadData() {
std::ifstream fs("data.dat", std::ios::binary);
if (!fs) throw std::runtime_error("Open failed");
fs.read(buf, 1024);
if (!fs) throw std::runtime_error("Read failed");
}
void PrintData() {
try {
ReadData();
for (int i=0;i<1024;i++) printf("%x ", buf[i]);
} catch (const std::exception& e) {
AfxMessageBox(CString(e.what()));
}
}
try {
// 可能拋出例外的代碼
CFile file(_T("data.dat"), CFile::modeRead);
file.Read(buf, 1024);
}
catch (CFileException* e) {
TCHAR szErr[256];
e->GetErrorMessage(szErr, 256);
AfxMessageBox(szErr);
e->Delete(); // 必須釋放
}
catch (CMemoryException* e) {
AfxMessageBox(_T("記憶體不足"));
e->Delete();
}
catch (CException* e) { // 兜底
e->ReportError(); // 顯示標準錯誤訊息
e->Delete();
}
區域物件析構函數在堆疊展開時自動執行,確保資源釋放:
鐵律:裸指標擁有權必須交給 RAII 包裝器,禁止在 `try` 區塊中手動 `new`/`delete` 配對。
在 DLL 中拋出 MFC 例外跨越模組邊界需注意模組狀態管理,建議在 DLL 介面函數入口加入 `AFX_MANAGE_STATE(AfxGetStaticModuleState())`,並在 EXE 端捕捉 `CException*`。