對於new來講算法
計算所需內存的字節數,而後以此爲參數調用標準庫的operator new(size_t)函數數組
在operator new()返回的內存上調用類的適當的構造函數初始化一個對象函數
將operator new() 返回的指針做爲表達式的運算結果spa
也即 new 把內存分配與對象構造合在一塊兒了指針
對於delete來講code
調用指針所指對象的析夠函數釋放對象自己對象
調用標準庫的operator delete()函數將指針所指內存返還給系統繼承
也即 delete 把釋放對象自己與釋放對象所佔的內存合在一塊兒內存
new[] 與 delete[] 行爲與上相似編譯器
不少時候並不須要當即在分配的內存上初始化一個對象,與此同時也但願在釋放內存以前不調用對象的析鉤函數;allocator類提供了這種機制,其成員:
allocator<T> a; /* a能夠用來分配原始內存以及在原始內存上構造T類型對象 */ a.allocate(n); /* 分配原始的內存,能夠保存n個Type類型的對象 */ a.deallocate(p,n);/* 釋放p所指的原始內存,p必須合法;而且不會調用p所指對象的析鉤函數,n表示p所指的內存能夠保存n個T類型對象 */ a.construct(p,t);/* 在p所指的內存上調用T類型的複製構造函數(以t爲參數)初始化一個對象 */ a.destory(p);/* 調用p所指對象的析鉤函數 */
若干個用於在原始內存上構造對象的算法:
uninitialized_copy(begin,end,begin2); /* 從迭代器[begin,end)指出的輸入範圍將元素複製到從迭代起begin2 * 開始的未構造的原始內存中,該函數是在目的地構造對象,而不是賦值 */ uninitialized_fill(begin,end,t) /* 將由迭代器[begin,end)指出的範圍中的對象初始化爲t的副本 * [begin,end)範圍是未構造的原始內存,使用複製構造函數構造對象 */ uninitialized_fill_n(begin,end,t,n) /* 同上,不過至多構造n個對象 */
標準庫提供了下列函數用於分配/釋放原始的未構造的內存:
void* operator new(size_t) /* new表達式調用 */ void* operator new[](size_t) /* new[]表達式調用 */ void operator delete(void*) void operator delete[](void*)
用來在已經分配好的,原始的內存上調用構造函數初始化對象,與其餘new表達式不一樣,定位new表達式不會分配新的內存,其語法:
/* 在已經分配的原始內存上調用對象的默認構造函數構造對象 */ new(原始內存指針) Type /* 根據參數類型與參數個數調用合適的構造函數構造對象 */ new(原始內存指針) Type(初始化參數)
#include <stdio.h> #include <new> #include <malloc.h> class Test{ public: Test(){ printf("1\n"); } Test(int __a,int __b){ printf("2\n"); } ~Test(){ ; } }; int main(int argc,char *argv[]){ Test *ptr=(Test*)malloc(sizeof(Test)); new(ptr)Test; ptr->~Test(); new(ptr)Test(3,3); ptr->~Test(); free(ptr); return 0; }
不能重定義new與delete表達式的行爲,可是能夠自定義new與delete表達式的行爲
當編譯器看到類類型的new或delete表達式時,她查看該類是否有operator new 或operator delete成員
類定義(或繼承)了本身的成員new和delete函數,則使用這些函數爲對象分配/釋放原始內存
不然,調用這些函數的標準庫版本
#include <stdio.h> #include <new> #include <malloc.h> class Test{ public: void* operator new(size_t __size){ printf("1\n"); return ::operator new(__size); } }; int main(int argc,char *argv[]){ Test *test=new Test; delete test; return 0; }
自定義operator new與operator delete時只要注意參數類型,返回值類型便可
#include <stdio.h> #include <new> #include <malloc.h> class Test{ public: void operator delete(void* __p,size_t __size){ printf("Size: %zd\n",__size); /* __size無關緊要,若__size存在,編譯器會把'delete p' * p所指對象所佔內存字節傳遞給__size */ ::operator delete(__p); return ; } }; int main(int argc,char *argv[]){ Test *test=new Test; delete test; return 0; }
對於operator new:
#include <stdio.h> #include <new> #include <malloc.h> class A{ public: void* operator new(size_t __size){ printf("A\n"); return ::operator new(__size); } }; class B:public A{ public: void* operator new(size_t __size){ printf("B\n"); return ::operator new(__size); } }; int main(int argc,char *argv[]){ A *a=new A;/* 調用A的operator new */ A *b=new B;/* 調用B的operator new */ /* 分析new表達式的行爲->與 B *b=new B 是同樣的狀況 */ delete a; delete b; return 0; }
對於 operator delete,B繼承A,當B中未定義operator delete時:
#include <stdio.h> #include <new> #include <malloc.h> class A{ public: void operator delete(void *__p,size_t __size){ printf("Size: %zd\n",__size); ::operator delete(__p); } virtual ~A(){ ; } }; class B:public A{ int a; }; int main(int argc,char *argv[]){ A *a=new A; A *b=new B; delete a;/* a->A類型的對象,因此__size=sizeof(A) */ delete b; /* 因爲A中存在虛析夠函數,因此編譯器會將b所指動態類型的 * 尺寸傳遞給__size,即__size=sizeof(B) */ return 0; }
當B中也定義了operator delete時:
#include <stdio.h> #include <new> #include <malloc.h> class A{ public: void operator delete(void *__p,size_t __size){ printf("A:Size: %zd\n",__size); ::operator delete(__p); } virtual ~A(){ ; } }; class B:public A{ int a; void operator delete(void *__p,size_t __size){ printf("B:Size: %zd\n",__size); ::operator delete(__p); } }; int main(int argc,char *argv[]){ A *a=new A; A *b=new B; delete a; /* 調用A::operator delete */ delete b; /* 調用的是B::operator delete */ return 0; }
在delete b 中調用的 B::operator delete 有一點疑惑不解,因爲 operator new()與operator delete()在類中默認是靜態成員函數(由於當 A *a=new A時,分配內存會先於對象構造,因此應該是靜態函數) 因此她們 不可能同時又是虛函數,因此delete b應該調用的是A::operator delete;可是確確實實調用的是B::operator delete;想來大概是編譯器的做用,記住就行
與上很是類似,如不在類繼承層次中的自定義:
#include <stdio.h> #include <new> #include <malloc.h> class A{ public: A(){ printf("A\n"); } void* operator new[](size_t __size){ printf("A:new Size: %zd\n",__size); return ::operator new[](__size); } void operator delete[](void *__p,size_t __size){ printf("A:delete Size: %zd\n",__size); ::operator delete[](__p); return ; } virtual ~A(){ printf("~A\n"); } }; int main(int argc,char *argv[]){ A *a=new A[4]; delete[] a;/* 會把a所指內存的字節(即數組大小)傳遞給__size */ return 0; }
在類繼承層次:
#include <stdio.h> #include <new> #include <malloc.h> class A{ public: A(){ printf("A\n"); } void* operator new[](size_t __size){ printf("A:new Size: %zd\n",__size); return ::operator new[](__size); } void operator delete[](void *__p,size_t __size){ printf("A:delete Size: %zd\n",__size); ::operator delete[](__p); return ; } void operator delete(void *__p,size_t __size){ printf("A:delete Size: %zd\n",__size); ::operator delete(__p); return ; } virtual ~A(){ printf("~A\n"); } }; class B:public A{ int b; public: B():b(0){ printf("B\n"); } void* operator new[](size_t __size){ printf("B:new Size: %zd\n",__size); return ::operator new[](__size); } void operator delete[](void *__p,size_t __size){ printf("B:delete Size: %zd\n",__size); ::operator delete[](__p); return ; } void operator delete(void *__p,size_t __size){ printf("B:delete Size: %zd\n",__size); ::operator delete(__p); return ; } virtual ~B(){ printf("~B\n"); } }; int main(int argc,char *argv[]){ A *b=new B; delete b;/* 正確釋放 */ B *b2=new B[4]; delete[] b2;/* 能夠正確釋放 */ A *b1=new B[4]; delete[] b1;/* 此時提示段錯誤,編譯器不能識別了... */ // delete[] (B*)b1 /* 便可 */ return 0; }
注意 delete[] b1 出錯!