當 operator new 分配記憶體失敗時,會拋出 bad_alloc 異常,**在此之前**會反覆呼叫由 std::set_new_handler() 設定的錯誤處理函數(new-handler)。
namespace std {
typedef void (*new_handler)();
new_handler set_new_handler(new_handler p) throw();
}
throw() 表示不拋出異常。nullptr)。bad_alloc 或衍生異常。abort() 或 exit()。C++ 無內建型別相關 handler,需自行實作:重載 operator new,暫時替換全域 handler。
class Widget {
public:
static std::new_handler set_new_handler(std::new_handler p) throw();
static void* operator new(std::size_t size) throw(std::bad_alloc);
private:
static std::new_handler currentHandler;
};
std::new_handler Widget::currentHandler = 0;
std::new_handler Widget::set_new_handler(std::new_handler p) throw() {
std::new_handler old = currentHandler;
currentHandler = p;
return old;
}
void* Widget::operator new(std::size_t size) throw(std::bad_alloc) {
std::new_handler globalHandler = std::set_new_handler(currentHandler);
void* p = ::operator new(size); // 呼叫全域 new
std::set_new_handler(globalHandler); // 恢復
return p;
}
若 ::operator new 拋出異常,需確保全域 handler 被恢復 → 使用 RAII 包裝器。
class NewHandlerHolder {
public:
explicit NewHandlerHolder(std::new_handler nh) : handler(nh) {}
~NewHandlerHolder() { std::set_new_handler(handler); }
private:
std::new_handler handler;
// 禁用拷貝
NewHandlerHolder(const NewHandlerHolder&);
NewHandlerHolder& operator=(const NewHandlerHolder&);
};
void* Widget::operator new(std::size_t size) throw(std::bad_alloc) {
NewHandlerHolder h(std::set_new_handler(currentHandler));
return ::operator new(size); // 異常時析構函數自動恢復 handler
}
templateclass NewHandlerSupport { public: static std::new_handler set_new_handler(std::new_handler p) throw(); static void* operator new(std::size_t size) throw(std::bad_alloc); private: static std::new_handler currentHandler; }; template std::new_handler NewHandlerSupport ::currentHandler = 0; template std::new_handler NewHandlerSupport ::set_new_handler(std::new_handler p) throw() { std::new_handler old = currentHandler; currentHandler = p; return old; } template void* NewHandlerSupport ::operator new(std::size_t size) throw(std::bad_alloc) { NewHandlerHolder h(std::set_new_handler(currentHandler)); return ::operator new(size); }
使用:class Widget : public NewHandlerSupport
模板參數 T 僅為了讓每個類別擁有獨立的靜態 currentHandler。
Widget* p1 = new Widget; // 失敗拋 bad_alloc
Widget* p2 = new (std::nothrow) Widget; // 失敗回傳 nullptr
if (!p2) { /* 處理失敗 */ }
new 失敗回傳 0,現標準預設拋異常。