用C++模板來展示new與delete操作符原理
阿新 • • 發佈:2019-01-29
C++中的new與delete可以認為是C中的malloc與free的升級版本。
new包含兩部分,一部分是與malloc功能相同,是從堆上面申請記憶體塊,第二部是呼叫類的構造方法來初始化剛申請的記憶體。
delete是new的逆過程,先呼叫類的析構方法來反初始化,再把剛申請的記憶體還給堆。
new [] 與delete []是針對陣列操作符,要注意是通過new []分配的物件,不能用delete來釋放物件,否則會有記憶體洩漏。當然通過new分配的物件,不能用delete[]來釋放物件。後面我會通過程式碼來說明為什麼。
下面是C++ 中的new與delete函式原型,申請記憶體失敗會丟擲異常bad_alloc
- void* operator new(std::size_t) throw (std::bad_alloc);
- void* operator new[](std::size_t) throw (std::bad_alloc);
- void operator delete(void*) throw();
- void operator delete[](void*) throw();
使用舉例
- int* p1 = newint();
- delete p2;
- int* p2 = newint[5];
- delete [] p2;
終於到了用模板來模擬new與delete操作符,程式碼中有註釋說明,其中對於呼叫類的構造方法,採用一種C++標準中稱作in-place construtor的方式。使用原型為T* = new(pbuff) T(),直譯的話就是在pbuff這塊記憶體構造T類,而不用再去堆上面申請記憶體。這種技巧大量應用在物件池的實現中,即pbuff這塊記憶體可以掛在連結串列中反覆地使用(這裡先不展開說了)。
- /**
- * A simulation of c++ new T() & new T(param) operation
- */
- struct NewObj
- {
- template <typename T>
- inlinevoid operator()(T*& pObj)
- {
- // allocate memory form heap
- void * pBuff = malloc(sizeof(T));
- // call constructor
-
pObj = new
- }
- template <typename T, typename P>
- inlinevoid operator()(T*& pObj, const P& param)
- {
- // allocate memory form heap
- void * pBuff = malloc(sizeof(T));
- // call constructor, pass one param
- pObj = new(pBuff) T(param);
- }
- };
- /**
- * A simulation of c++ delete T operation
- */
- struct DeleteObj
- {
- template <typename T>
- inlinevoid operator()(T*& pObj)
- {
- if ( NULL == pObj ) { return ;}
- // call destructor
- pObj->~T();
- // free memory to heap
- free((void*)pObj);
- pObj = NULL;
- }
- };
- /**
- * A simulation of c++ new T[N]() operation
- */
- struct NewObjArray
- {
- template <typename T>
- inlinevoid operator()(T*& pObj, unsigned int size)
- {
- // save the number of array elements in the beginning of the space.
- long * pBuff = (long *) malloc (sizeof(T) * size + sizeof(long));
- *((unsigned int *) pBuff) = size;
- pBuff++;
- // change pointer to T type, then can use pT++
- T * pT = (T *) pBuff;
- // save the pointer to the start of the array.
- pObj = pT;
- // now iterate and construct every object in place.
- for (unsigned int i = 0; i < size; i++)
- {
- new((void *) pT) T();
- pT++;
- }
- }
- };
- /**
- * A simulation of c++ delete [] T operation
- */
- struct DeleteObjArray
- {
- template <typename T>
- inlinevoid operator()(T*& pObj)
- {
- unsigned int size = *((unsigned int *) ((long *) pObj - 1));
- T * pT = pObj;
- // call destructor on every element in the array.
- for (unsigned int i = 0; i < size; i++)
- {
- pT->~T();
- pT++;
- }
- // free memory to heap.
- free ((void *) ((long *) pObj - 1));
- pObj = NULL;
- }
- };
測試程式碼
- struct TestClass
- {
- TestClass() : mem1(0), mem2(0) {}
- TestClass(int m) : mem1(m), mem2(0) {}
- int mem1;
- long mem2;
- };
- void test_new_delete()
- {
- TestClass* p1 = NULL;
- NewObj()(p1);
- printf("%p/n", p1);
- DeleteObj()(p1);
- //
- TestClass* p2 = NULL;
- NewObj()(p2, 0);
- printf("%p/n", p2);
- DeleteObj()(p2);
- //
- TestClass* p3 = NULL;
- NewObjArray()(p3, 5);
- printf("%p/n", p3);
- DeleteObjArray()(p3);
- }
Note:測試環境為eclipse+cdt+ubuntu+gcc,注意標頭檔案需要#include <new>,使用#include <stdlib.h>會導致編譯不過,因為in-place construtor是C++中的新玩意。