VC6 預設 operator new 失敗傳回 NULL,但 C++ 標準要求拋出 std::bad_alloc。STL 內部假設 new 會拋出異常,若實際傳回 NULL,會導致未定義行為(如存取 0x1 位址),使應用程式崩潰。
| 環境 | new 失敗行為 |
|---|---|
| VC6 非 MFC | 傳回 NULL |
| VC6 + MFC | 拋出 CMemoryException |
| VC.NET (7.0/7.1) 非 MFC | 拋出 std::bad_alloc (標準) |
| VC.NET + MFC | 拋出 CMemoryException (非標準型別) |
唯有 VC.NET 非 MFC 專案符合標準,STL 能正確捕捉 bad_alloc。
std::string 建構時呼叫 allocator::allocate → operator new。若傳回 NULL,後續 _Ptr = _S + 1 變為 0x1,隨後 _Refcnt(_Ptr) = 0 解參考 0x0 → 存取違規。
NewHandler.cpp,於 _set_new_handler 註冊處理函數,失敗時拋出 std::bad_alloc。勿使用 _set_new_mode(1)(會影響 malloc 及 new(nothrow))。new(nothrow) 仍拋出異常。需自行實作傳回 NULL 的版本,但注意:若連結 DLL CRT,會影響同一進程內所有模組。new(nothrow),可規避問題。VC6 非 MFC 專案使用 STL 時,必須 安裝 new-handler 將 new 失敗轉為標準異常,否則記憶體不足時極大機率崩潰。VC.NET 已修正此問題。MFC 專案視 STL 實作而定(多用 catch(...) 較安全)。