【理論實踐】new的三種用法:plain new,nothrow new和placement new
阿新 • • 發佈:2019-02-12
一、plain new就是最普通的new的,動態建立一個物件或陣列,基本用法如下:
class A { int m_v; public: A() {} A(int v) : m_v(v) {} A(double v) : m_v(ceil(v)) {} }; A* p1 = new A; //非必要情況不會呼叫合成的建構函式 A* p2 = new A(); //必然呼叫建構函式,如果沒有,呼叫合成建構函式 A* p3 = new A(3); //呼叫int引數構造 A* p4 = new A(3.1); //呼叫double型別構造 A* p5 = new A[2]; //分配2個元素陣列,非必要不初始化 A* p6 = new A[2](); //分配2個元素,初始化 A* p7 = new A[2](3); //非法呼叫,動態分配陣列不能指定帶引數的建構函式 // delete p1; delete p2; delete p3; delete p4; delete [] p5; delete [] p6;
二、nothrow new不拋異常的new
如果記憶體不足,new預設會拋異常std::bad_alloc,大部分情況我們希望記憶體不足時立即停止,否則在動態分配記憶體時,還需要增加非常多的分支,處理邏輯複雜N倍。但是,如果有時候,我們是有辦法解決記憶體不足的,比如等待一會兒,尤其是服務端程式比較常見,這個時間, 我們希望自己來處理記憶體不足。在大塊記憶體申請上,更容易遇到。首先想到的可能是用try catch,程式碼如下
try {
p1 = new A();
} catch (std::bad_alloc) {
//等待並重試
}
其實,nothrow new就是解決這個場景的,如果記憶體不足,返回nullptr而不是拋異常,用法如下:
p1 = new(nothrow) A; if(p1 == nullptr) ;//等待並重試
三、placement new,直譯“只放置的new",這個new並不分配記憶體,僅初始化,非常有用,我們可以顯示的去重複呼叫建構函式,是記憶體池的基礎,allocator實現必然用到。多一個引數傳遞一個記憶體空間,不要求大小一致,只要大於物件即可,這樣,大物件的記憶體資源是可以複用給小物件的。用法如下:
p1 = new (buf) A[2];
p1->~A();
delete p1; //core
如上,複用的new,必須不能被delete,否則core異常,而是要顯示的呼叫解構函式。