1. 程式人生 > >【理論實踐】new的三種用法:plain new,nothrow new和placement new

【理論實踐】new的三種用法:plain new,nothrow new和placement new

一、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異常,而是要顯示的呼叫解構函式。