在通常的情況下,調用new操作的時候,一般都不會去關心是否有足夠的記憶體使得這個操作可以成功。但是做為一個完美的程式,有必要去處理一下記憶體不夠的情況。
在預設情況下,記憶體配置失敗會導致返回null或者拋出一個std::bad_alloc異常,所以需要在每次new的時候檢查傳回值是否為NULL或者在new上包裹一個try catch塊。不過,除了每次不厭其煩得關心new是否成功,我們可以利用C++提供的set_new_handler函數來註冊一個記憶體配置失敗後的回呼函數。set_new_handler函數接受一個如下定義的函數指標:
typedef void ( *new_handler )( );
當可用記憶體不足導致new操作失敗的時候,如果有註冊一個new_handler, new操作內部就會反覆調用你註冊的handler,然後重新嘗試分配記憶體(所以你可以利用new_handler來釋放一些不需要的記憶體,保證程式順利運行)。當然,如果你沒有註冊new_handler,它就要拋出一個異常了。具體可以參考下面這段代碼:
while ((p = malloc(size)) == 0)
if (_callnewh(size) == 0)
{ // report no memory
static const std::bad_alloc nomem;
_RAISE(nomem);
}
return (p);
總結一下new_handler的用處
1 釋放記憶體,保證new操作順利執行
2 方便對new操作的異常處理,只需要註冊一次,不需要每次在new操作之後檢查或者捕捉異常
下面是new操作的用法舉例:
1. 記憶體不足時,寫log,然後釋放不需要的記憶體
#include "stdafx.h"
#include <iostream>
#include <limits.h>
using namespace std;
void myHandler()
{
cerr<<"error doing new"<<endl;
//可以在這裡釋放一些記憶體
}
int _tmain(int argc, _TCHAR* argv[])
{
set_new_handler(myHandler);
int MemoryNeed = INT_MAX;
void *p = ::operator new(MemoryNeed);
return 0;
}
2. 也可以在首次調用new_handler之後更改/移除處理函數,實現靈活的記憶體配置邏輯:
#include "stdafx.h"
#include <iostream>
#include <limits.h>
using namespace std;
void myHandler2()
{
cerr<<"new way to handler insufficient memory"<<endl;
//在第二次執行後移除處理函數,利用預設機制拋出異常
set_new_handler(NULL);
}
void myHandler()
{
cerr<<"error doing new"<<endl;
//在第一次執行後設定新的處理函數
set_new_handler(myHandler2);
}
int _tmain(int argc, _TCHAR* argv[])
{
set_new_handler(myHandler);
int MemoryNeed = INT_MAX;
void *p = ::operator new(MemoryNeed);
return 0;
}
輸出結果如下: