c++中new和delete的使用方法

liangweibeijing發表於2012-11-03

摘自:http://www.cnblogs.com/jjzhou1988/archive/2008/11/30/1344314.html

 

new和delete運算子用於動態分配和撤銷記憶體的運算子

new用法:

          1.     開闢單變數地址空間

               1)new int;  //開闢一個存放陣列的儲存空間,返回一個指向該儲存空間的地址.int *a = new int 即為將一個int型別的地址賦值給整型指標a. 

               2)int *a = new int(5) 作用同上,但是同時將整數賦值為5

          2.     開闢陣列空間

               一維: int *a = new int[100];開闢一個大小為100的整型陣列空間

               二維: int **a = new int[5][6]

               三維及其以上:依此類推.

         一般用法: new 型別 [初值]

delete用法:

          1. int *a = new int;

               delete a;   //釋放單個int的空間

          2.int *a = new int[5];

               delete [] a; //釋放int陣列空間

 

          要訪問new所開闢的結構體空間,無法直接通過變數名進行,只能通過賦值的指標進行訪問.

          用new和delete可以動態開闢,撤銷地址空間.在程式設計序時,若用完一個變數(一般是暫時儲存的陣列),下次需要再用,但卻又想省去重新初始化的功夫,可以在每次開始使用時開闢一個空間,在用完後撤銷它.

---------------------------------------------------------------------------------------------
                                Follow   the another relative
---------------------------------------------------------------------------------------------
 
/*****************************************************************************/
/*                        C++中的 new / delete                               */
/*****************************************************************************/
/*
    new的3種形態: new operator , operator new , placement new

    new operator:
        new操作符,像 + - * / && . :: ?: 等操作符一樣,是語言內建的, 它
        不能被過載,不能改變其行為。
        它的行為包括分配記憶體的 operator new 和呼叫建構函式的 placement new。
        new operator 實際上做了三件事:獲得一塊記憶體空間、呼叫建構函式、返回
        正確的指標。如果建立的是簡單型別(如char)的變數,那麼第二步會被省略。
        比如:
            CTest* pT = new CTest(1, 2);
        它的呼叫實際上等效於:
            void*  p  = operator new( sizeof(CTest) );
            CTest* pT = new(p) CTest(2, 2);
        其中前一句是operator new分配記憶體,後一句是placement new呼叫構造函
        數,並返回正確的CTest*指標。


    operator new:
        操作符new,原型為:
            void* operator new(size_t size);
        它分配指定大小的記憶體, 可以被過載, 可以新增額外的引數, 但第一個引數
        必須為 size_t 。
        它除了被 new operator 呼叫外也可以直接被呼叫, 如:
            void* p = operator new(sizeof(CTest));
        這種用法和呼叫 malloc 一樣, 只分配了sizeof(CTest)大小的記憶體。
       
    placement new:
        置換new,原型為:
         void operator new(size_t size,void*p);
        它在一塊指定的記憶體上呼叫建構函式, 包含標頭檔案<new>之後也可
        以直接使用,如:
            CTest* pT = new(p) CTest(2, 2);
        他在p這塊記憶體上呼叫CTest的建構函式來初始化CTest。
        如果用 placement new 構造出來的物件,必須顯示的呼叫物件的解構函式,
        如:
            pT->~CTest();
        然後釋放能存, 呼叫 operator delete (對應於分配時的 operator new)
            operator delete(pT);


    delete operator:
        delete操作符,和 new operator 一樣,不能被過載,不能改變其行為。
        delete operator 做的事有:呼叫解構函式,然後呼叫operator delete來
        釋放記憶體,比如:
            delete pT;
        它的呼叫實際上等效於:
            pT->~CTest();
            operator delete(pT);

    operator delete:
         操作符delete,原型為:
         void*operator delete(void *p)
        同理,對應於分配記憶體的 operator new,釋放記憶體的為 operator delete ,
        它也可以被過載。
   
    operator new []
    operator delete []
        也是同樣原理 ....

******************************************************************************/


/*****************************************************************************/
/*                        new 的基本使用指南                                 */
/*****************************************************************************/
/*
    1)、想在堆上建立一個物件,應該用 new 操作符,它既分配記憶體又為物件呼叫構
        造函式。

    2)、如果僅僅想分配記憶體,就應該呼叫 operator new 函式;它不會呼叫建構函式。
   
    3)、如果想定製在堆物件被建立時的記憶體分配過程,應該過載 operator new 函式,
        然後使用 new operator,new operator 會呼叫定製的 operator new 。

    4)、如果想在一塊已經獲得指標的記憶體裡建立一個物件,應該用 placement new 。
        placement new 主要適用於:
            (a): 對時間要求非常高的應用程式中,因為這些程式分配的時間是確定的;
            (b): 長時間執行而不被打斷的程式;
            (c): 以及執行一個垃圾收集器 (garbage collector) 。

    注意:如果用 placement new 構造出來的物件,必須顯示的呼叫物件的解構函式。

******************************************************************************/


/*****************************************************************************/
/*                          delete this                                      */
/*****************************************************************************/
/*
    如上所述,呼叫 delete pT; 的執行可以看作如下這樣一個過程:
        pT->~CTest();
        operator delete(pT);
    其中:
        pT->~CTest() 語句呼叫解構函式。(解構函式本身是不會釋放記憶體的)
        operator delete(pT) 釋放記憶體。 (這是一個物件在消亡之前的最後動作)
   
        若CTest類過載了operator delete(), 那麼將不呼叫全域性的operator delete(pT),
    而是呼叫 pT->operator delete(pT)(在CTest::operator delete()內最好還應該呼叫
    全域性的operator delete來釋放記憶體)。

    問:成員函式呼叫 delete this 合法嗎?
    答:只要你小心,一個物件請求自殺(delete this),是可以的!
 

    以下是對 "小心" 的定義:
 
        1)、必須100%的確定:物件是用 new 分配的(不是用new[],也不是用
            placement new,也不是一個棧上的區域性物件,也不是全域性的,也不
            是另一個物件的成員,而是明白的普通的 new )。

        2)、必須100%的確定:該成員函式是物件最後呼叫的的成員函式。

        3)、必須100%的確定:該成員函式在 delete this 之後的程式碼中不接觸到
            物件的任何一塊(包括呼叫任何其他成員函式或訪問任何資料成員)。

        4)、必須100%的確定:在 delete this 之後不再去訪問this指標。你不能
            去檢查它,將它和其他指標比較,和NULL比較,列印它,轉換它...,
            不能對它做任何事。

            自然,對於這種情況還要習慣性地告誡:當你的指標是一個指向基類類
            型的指標,而沒有虛解構函式時(也不可以delete this)。因為是在類
            成員函式裡面delete this的,所以在此語句以後,不能訪問任何成員變
            量及虛擬函式(呼叫虛擬函式必須物件例項存在以檢查型別),否則一定非法。
   
        上面所說的情況,在執行時不一定會報錯,但儘量不要這麼做。因為,一般來
    說,記憶體釋放釋放的只能是資料段的內容(包括堆和棧,但釋放棧上的記憶體由系統
    進行),而程式碼段的記憶體在記憶體中是永遠不會釋放/改變的,直到程式結束。因此
    在記憶體釋放後也是可以訪問的。所以,一般所謂的釋放記憶體delete操作,是在資料
    段進行的釋放。但是,並不要因為這樣,就違背上面的原則。

******************************************************************************/


/*-----------* 下面是 new 應用例項 *----------------------------------------------*/
/*
    F1 中的 new operator,他的行為就像F2中的 operator new 和 placement new 一樣,
    也可以用F3中的方法達到相同的效果。
*/

#include <new>
#include <stdio.h>

class CTest
{
public:
    CTest(int _x, int _y)
    {
        X = _x;
        Y = _y;
    }
    ~CTest()
    {
        X = 0;
        Y = 0;
    }
    void Test(char* sz)
    {
        printf("%s: X=%d Y=%d /n", sz, X, Y);
    }
    int X;
    int Y;
};

/*
    new operator:
*/
void F1()
{
    CTest* pT = new CTest(1, 1);             // new operator
   
    pT->Test("F1");

    delete pT;

}

/*
    operator new
    placement new
*/
void F2()
{
    void*  p  = operator new(sizeof(CTest)); // operator new : 分配記憶體
    CTest* pT = new(p) CTest(2, 2);          // placement new: 構造物件
   
    pT->Test("F2");
   
    pT->~CTest();                            // 必須顯示析構物件
    operator delete(pT);                     // operator delete: 釋放記憶體
}

/*
    也可這樣實現:
*/
void F3()
{
    char*  p  = new char[sizeof(CTest)]; // new operator: char為內建型別,不會呼叫建構函式,相當於只分配記憶體

    CTest* pT = new(p) CTest(3, 3);      // placement new: 在這塊記憶體上構造CTest物件
   
    pT->Test("F3");
   
    pT->~CTest();                        // 必須顯示析構CTest物件

    delete [] p;                         // delete operator: char為內建型別,不會呼叫解構函式,相當於只釋放記憶體
}


void main()
{
    F1();
    F2();
    F3();
}

 

相關文章