當operator new無法滿足某一記憶體分配時,就會丟擲一次。以前它會返回null指標,現在某些舊式編譯器也還這麼做。
namespace std
new_handler是個函式指標,該函式沒有引數也不返回任何東西。set_new_handler是設定乙個new_handler並返回乙個new_handler函式,返回的new_handler是指向set_new_handler被呼叫前正在執行的那個new-handler函式。後面的throw是乙份異常明細,表示該函式不丟擲異常。可以這樣使用
#include using namespace std;
void outofmem()
int main()
設計良好的new-handler必須做好以下事情:
有時候,我們希望處理記憶體分配失敗的情況和class相關。例如
class x;
class y;
x* p1=new x;//分配不成功,呼叫x::outofmemory
y* p2=new y;//分配不成功,呼叫y::outofmemory
c++並不支援class專屬的new-handler,但是我們自己可以實現這種行為。令每乙個class提供自己的set_new_handler和operator new即可。……………………………………………………………………………………
現在打算處理widget class記憶體分配失敗的情況。首先要有乙個operator new無法為widget分配足夠記憶體時的呼叫函式,即new_handler函式
class widget;
std::new_handler widget::currenthandler=0;
std::new_handler widget::set_new_handler(std::new_handler p) throw()
widget的operator new做以下事情:
1、呼叫標準set_new_handler,告知widget錯誤處理函式。這會將widget的new-handler安裝為global new-handler。
2、呼叫global operator new,如果失敗,global operator new會呼叫widget的new-handler,因為第一步。如果global operator new最終無法分配足夠記憶體,會丟擲乙個bad_alloc異常。這時widget的operator new要恢復原本的global new-handler,之後在傳播異常。
3、如果global operator new呼叫成功,widget的operator new會返回乙個指標,指向分配的記憶體。widget析構函式會管理global new-handler,它會將widget』s operator new被呼叫前的那個global new-handler恢復回來。
class newhandlerholder
~newhandlerholder()
private:
std::new_handler handler;
newhandlerholder&(const newhandlerholder&);//防止copying
newhandlerholder& operator-(const newhandlerholder&);
};
這使得widget』s operator new的實現變得簡單
void* widget::operator new(std::size_t size) throw(std::bad_alloc)
widget客戶應該類似這樣使用其new-handling
void outofmem();
widget::set_new_handler(outofmem);//設定outofmem為widget的new-handling函式
widget* pw1=new widget;//記憶體分配失敗,則呼叫outofmem
std::string* ps=new std::string;//記憶體分配失敗則呼叫global new-handling(如果有)
widget::set_new_handler(0);//設定widget專屬new-handling為null
widget* pw2=new widget;//記憶體分配失敗則立刻丟擲異常
實現這個方案的class**基本相同,用個基類base class加以復用是個好的方法。可以用個template base class,如此以來每個derived class將獲得實體互異的class data復件。這個base class讓其derived class繼承它獲取set_new_handler和operator new,template部分確保每乙個derived class獲得乙個實體互異的currenthandler成員變數。
templateclass newhandlersupport;
templatestd::new_handler
newhandlersupport::set_new_handler(std::new_handler p) throw()
templatevoid* newhandlersupport::operator new(std::size_t size)
throw(std::bad_alloc)
//將每乙個currenthandler初始化為null
templatestd::new_handler newhandlersupport::currenthandler=0;
有了這個class template,為widget新增set_new_handler就容易了
class widget:public newhandlersupport;
在template base class中,從未使用型別t。因為currenthandler是static型別,使用模板的話會是每個class都有自己的currenthandler。如果使用多重繼承,要注意**條款**40所提到的內容。
c++中operator new分配失敗丟擲異常bad_alloc,但是舊標準是返回null指標。舊標準這個形式為nothrow形式。
class widget{};
widget* pw1=new widget;//分配失敗,丟擲bad_alloc
if(pw1==null)//判斷是否分配成功。但是這個測試失敗
widget* pw2=new(std::nothrow)widget;//分配失敗,返回null
if(pw2==null)//可以偵測
new(std::nothrow) widget發生兩件事,第一分配記憶體給widget物件,如果失敗返回null指標。第二,如果成功,呼叫widget的建構函式,但是在這個建構函式做什麼,nothrow new並不知情,有可能再次開闢記憶體。如果在建構函式使用operator new開闢記憶體,那麼還是有可能丟擲異常並傳播。使用nothrow new只能保證operator new不丟擲異常,不能保證像new(std::nothrow) widget這樣的表示式不丟擲異常。所以,並沒有運用nothrow的需要。總結
條款49 了解new handle行為
多執行緒下的記憶體管理與單執行緒下是完全不同的,因為heap是乙個可以被全域性改動的資源,所以所有的執行緒都有可能去訪問這一資源,這回導致很多的race conditions。當operator new未取得想要的記憶體的時候,會呼叫乙個使用者指定的處理函式,new handler。這個函式可以使用...
條款49 盡量讓自己熟悉C 標準庫
1,標準庫的每一樣東西幾乎都在namespace std中,然而世界上有無可計數的c 程式 依賴那些已經使用多年的 準 標準程式庫,例如宣告於,等檔案中的功能。2,解決方法,設計新的頭檔名,給披上std外衣的各個元件使用。1 將原有的c 標頭檔案中的.h擴充套件拿掉,於是變為。如 cin的型別 ba...
49 shell中的冒號
1 表示永真,相當於true關鍵字。colon.sh指令碼利用while迴圈列印1到10的整數,while迴圈的條件使用了冒號,此時冒號就表示永真,即while迴圈永遠執行下去,while迴圈體內使用if then結構判斷跳出while迴圈的條件。1 bin bash 2 3 i 0 4 while...