1. 程式人生 > >用C++模板來展示new與delete操作符原理

用C++模板來展示new與delete操作符原理

C++中的new與delete可以認為是C中的malloc與free的升級版本。

new包含兩部分,一部分是與malloc功能相同,是從堆上面申請記憶體塊,第二部是呼叫類的構造方法來初始化剛申請的記憶體。

delete是new的逆過程,先呼叫類的析構方法來反初始化,再把剛申請的記憶體還給堆。

new [] 與delete []是針對陣列操作符,要注意是通過new []分配的物件,不能用delete來釋放物件,否則會有記憶體洩漏。當然通過new分配的物件,不能用delete[]來釋放物件。後面我會通過程式碼來說明為什麼。

下面是C++ 中的new與delete函式原型,申請記憶體失敗會丟擲異常bad_alloc

  1. void* operator new(std::size_tthrow (std::bad_alloc);  
  2. void* operator new[](std::size_tthrow (std::bad_alloc);  
  3. void operator delete(void*) throw();  
  4. void operator delete[](void*) throw();  

 使用舉例

  1. int* p1 = newint();  
  2. delete p2;  
  3. int* p2 = newint[5];  
  4. delete [] p2;  

 終於到了用模板來模擬new與delete操作符,程式碼中有註釋說明,其中對於呼叫類的構造方法,採用一種C++標準中稱作in-place construtor的方式。使用原型為T* = new(pbuff) T(),直譯的話就是在pbuff這塊記憶體構造T類,而不用再去堆上面申請記憶體。這種技巧大量應用在物件池的實現中,即pbuff這塊記憶體可以掛在連結串列中反覆地使用(這裡先不展開說了)。

  1. /** 
  2.  * A simulation of c++ new T() & new T(param) operation 
  3.  */
  4. struct NewObj  
  5. {  
  6.     template <typename T>  
  7.     inlinevoid operator()(T*& pObj)  
  8.     {  
  9.         // allocate memory form heap
  10.         void * pBuff = malloc(sizeof(T));  
  11.         // call constructor
  12.         pObj = new
     (pBuff) T();  
  13.     }  
  14.     template <typename T, typename P>  
  15.     inlinevoid operator()(T*& pObj, const P& param)  
  16.     {  
  17.         // allocate memory form heap
  18.         void * pBuff = malloc(sizeof(T));  
  19.         // call constructor, pass one param
  20.         pObj = new(pBuff) T(param);  
  21.     }  
  22. };  
  23. /** 
  24.  * A simulation of c++ delete T operation 
  25.  */
  26. struct DeleteObj  
  27. {  
  28.     template <typename T>  
  29.     inlinevoid operator()(T*& pObj)  
  30.     {  
  31.         if ( NULL == pObj ) { return ;}  
  32.         // call destructor
  33.         pObj->~T();  
  34.         // free memory to heap
  35.         free((void*)pObj);  
  36.         pObj = NULL;  
  37.     }  
  38. };  
  39. /** 
  40.  * A simulation of c++ new T[N]() operation 
  41.  */
  42. struct NewObjArray  
  43. {  
  44.     template <typename T>  
  45.     inlinevoid operator()(T*& pObj, unsigned int size)  
  46.     {  
  47.         // save the number of array elements in the beginning of the space.
  48.         long * pBuff = (long *) malloc (sizeof(T) * size + sizeof(long));  
  49.         *((unsigned int *) pBuff) = size;  
  50.         pBuff++;  
  51.         // change pointer to T type, then can use pT++
  52.         T * pT = (T *) pBuff;  
  53.         // save the pointer to the start of the array.
  54.         pObj = pT;  
  55.         // now iterate and construct every object in place.
  56.         for (unsigned int i = 0; i < size; i++)  
  57.         {  
  58.             new((void *) pT) T();  
  59.             pT++;  
  60.         }  
  61.     }  
  62. };  
  63. /** 
  64.  * A simulation of c++ delete [] T operation 
  65.  */
  66. struct DeleteObjArray  
  67. {  
  68.     template <typename T>  
  69.     inlinevoid operator()(T*& pObj)  
  70.     {  
  71.         unsigned int size = *((unsigned int *) ((long *) pObj - 1));  
  72.         T * pT = pObj;  
  73.         // call destructor on every element in the array.
  74.         for (unsigned int i = 0; i < size; i++)  
  75.         {  
  76.             pT->~T();  
  77.             pT++;  
  78.         }  
  79.         // free memory to heap.
  80.         free ((void *) ((long *) pObj - 1));  
  81.         pObj = NULL;  
  82.     }  
  83. };  

 測試程式碼

  1. struct TestClass  
  2. {  
  3.     TestClass() : mem1(0), mem2(0)  {}  
  4.     TestClass(int m) : mem1(m), mem2(0) {}  
  5.     int mem1;  
  6.     long mem2;  
  7. };  
  8. void test_new_delete()  
  9. {  
  10.     TestClass* p1 = NULL;  
  11.     NewObj()(p1);  
  12.     printf("%p/n", p1);  
  13.     DeleteObj()(p1);  
  14.     //
  15.     TestClass* p2 = NULL;  
  16.     NewObj()(p2, 0);  
  17.     printf("%p/n", p2);  
  18.     DeleteObj()(p2);  
  19.     //
  20.     TestClass* p3 = NULL;  
  21.     NewObjArray()(p3, 5);  
  22.     printf("%p/n", p3);  
  23.     DeleteObjArray()(p3);  
  24. }  

 Note:測試環境為eclipse+cdt+ubuntu+gcc,注意標頭檔案需要#include <new>,使用#include <stdlib.h>會導致編譯不過,因為in-place construtor是C++中的新玩意。