new記憶體失敗後的正確處理

2021-07-13 12:26:26 字數 2976 閱讀 9033

應該有很多的程式設計師對比爾蓋茨的這句話有所耳聞:

對於任何乙個人而言,640kb應當是足夠的了。(640k ought to be enough for everybody.)

不幸的是,偉大的比爾蓋茨也失言了。隨著硬體水平的發展,記憶體變得越來越大,但是似乎仍不能滿足人們對記憶體日益增長的需求。所以呢,我們c/c++程式設計師在寫程式時也必須考慮一下記憶體申請失敗時的處理方式。

通常,我們在使用new進行記憶體分配的時候,會採用以下的處理方式:

char *pstr = new string[size];  

if(pstr == null)

你能發現上述**中存在的問題嗎?這是乙個隱蔽性極強的臭蟲(bug)。

我們沿用了c時代的良好傳統:使用 malloc 等分配記憶體的函式時,一定要檢查其返回值是否為「空指標」,並以此作為檢查分配記憶體操作是否成功的依據,這種test-for-null**形式是一種良好的程式設計習慣,也是編寫可靠程式所必需的。可是,這種完美的處理形式必須有乙個前提:若new失敗,其返回值必須是null。只有這樣才能保證上述看似「邏輯正確、風格良好」的**可以正確執行。

那麼new失敗後編譯器到底是怎麼處理的?在很久之前,即c++編譯器的蠻荒時代,c++編譯器保留了c編譯器的處理方式:當operator new不能滿足乙個記憶體分配請求時,它返回乙個null 指標。這曾經是對c的malloc函式的合理擴充套件。然而,隨著技術的發展,標準的更新,編譯器具有了更強大的功能,類也被設計得更漂亮,新時代的new在申請記憶體失敗時具備了新的處理方式:丟擲乙個bad_alloc exception(異常)。所以,在新的標準裡,上述test-for-null處理方式不再被推薦和支援。

如果再回頭看看本建議開頭的**片段,其中的 if (pstr == 0 )從良好的**風格突然一下變成了毫無意義。在c++裡,如果 new 分配記憶體失敗,預設是丟擲異常。所以,如果分配成功,pstr == 0就絕對不會成立;而如果分配失敗了,也不會執行if ( pstr == 0 ),因為分配失敗時,new 就會丟擲異常並跳過後面的**。

namespace

std

; }

/ new and delete

void *operator

new(std::size_t) throw(std::bad_alloc);

void

operator

delete(void *) throw();

// array new and delete

void *operator

new(std::size_t) throw(std::bad_alloc);

void

operator

delete(void *) throw();

// placement new and delete

void *operator

new(std::size_t, void *) throw();

void

operator

delete(void *, void *) throw();

// placement array new and delete

void *operator

new(std::size_t, void *) throw();

void

operator

delete(void *, void *) throw();

如果採用不丟擲異常的new形式,本建議開頭的**片段就應該改寫為以下形式:

int* pstr = new(std::nothrow) string[size];  

if(pstr==null)

根據建議29可知,編譯器在表示式 new (std::nothrow) classname中一共完成了兩項任務。首先,operator new 的 nothrow 版本被呼叫來為乙個classname object分配物件記憶體。假如這個分配失敗,operator new返回null指標;假如記憶體分配成功,classname 的建構函式則被呼叫,而在此刻,物件的建構函式就能做任何它想做的事了。如果此時它也需要new 一些記憶體,但是沒有使用 nothrow new形式,那麼,雖然在」new (std::nothrow) classname」 中呼叫的operator new 不會丟擲異常,但其建構函式卻無意中辦了件錯事。假如它真的這樣做了,exception就會像被普通的operator new丟擲的異常一樣在系統裡傳播。所以使用nothrow new只能保證operator new不會丟擲異常,無法保證」new (std::nothrow) classname」這樣的表示式不會丟擲exception。所以,慎用nothrow new。

最後還需要說明乙個比較特殊但是確實存在的問題:在visual c++ 6.0 中目前operator new、operator new(std::nothrow) 和 stl 之間不相容、不匹配,而且不能完全被修復。如果在非mfc專案中使用visual c++6.0中的stl,其即裝即用的行為可能導致stl在記憶體不足的情況下讓應用程式崩潰。對於基於mfc的專案,stl是否能夠倖免於難,完全取決於你使用的 stl 針對operator new的異常處理。這一點,在james hebben的文章《不要讓記憶體分配失敗導致您的舊版 stl 應用程式崩潰》中進行了詳細的介紹,如果你在使用古老的visual c++ 6.0編譯器,而且對這個問題充滿興趣,請google之。

請記住:

當使用new申請一塊記憶體失敗時,丟擲異常std::bad_alloc是c++標準中規定的標準行為,所以推薦使用try catch( std::bad_alloc ) 的處理方式。但是在一些老舊的編譯器中,卻不支援該標準,它會返回null,此時具有c傳統的test_for_null**形式便起了作用。所以,要針對不同的情形採取合理的處置方式。

C new記憶體失敗後的正確處理

1.new在申請記憶體失敗時的處理方式 丟擲乙個bad alloc異常。new delete void operator new std size t throw std bad alloc void operator delete void throw array new delete void ...

手機進水後的正確處理方法

toc如果手機不小心進水了。別慌,以下根據進水程度不同分別介紹處理方法。手機輕度進水,手機輕度進水指的是少量水灑到螢幕,外殼位置,這種情況一般是下雨雨滴,或者洗手後用手機時手上殘餘的水。這種情況如果水沒有滴入耳機孔裡面或者充電口裡面就沒事,無需特別處理,用紙巾擦乾就可以。如果有水滴入聽筒裡,聽筒音量...

new和malloc申請記憶體失敗後的處理

1.c 標準 new 失敗是丟擲異常的,visual c 6.0中返回乙個null指標.使用new std nothrow 可以保證失敗時返回null 因此完全可以 define new new std nothrow 2.使用 malloc calloc 等分配記憶體的函式時,一定要檢查其返回值是...