C++ new 與 delete

new與delete表達式做了什麼

對於new來講算法

  1. 計算所需內存的字節數,而後以此爲參數調用標準庫的operator new(size_t)函數數組

  2. 在operator new()返回的內存上調用類的適當的構造函數初始化一個對象函數

  3. 將operator new() 返回的指針做爲表達式的運算結果spa

也即 new 把內存分配與對象構造合在一塊兒了指針

對於delete來講code

  1. 調用指針所指對象的析夠函數釋放對象自己對象

  2. 調用標準庫的operator delete()函數將指針所指內存返還給系統繼承

也即 delete 把釋放對象自己與釋放對象所佔的內存合在一塊兒內存

new[] 與 delete[] 行爲與上相似編譯器

allocator類

不少時候並不須要當即在分配的內存上初始化一個對象,與此同時也但願在釋放內存以前不調用對象的析鉤函數;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個對象 */

operator new/operator delete

標準庫提供了下列函數用於分配/釋放原始的未構造的內存:

void* operator new(size_t)      /* new表達式調用 */
void* operator new[](size_t)    /* new[]表達式調用 */
void operator delete(void*)
void operator delete[](void*)

定位new表達式

用來在已經分配好的,原始的內存上調用構造函數初始化對象,與其餘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表達式的行爲
當編譯器看到類類型的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;
}


在類繼承層次中自定義new與delete

對於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;想來大概是編譯器的做用,記住就行

自定義new[]/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 出錯!

相關文章
相關標籤/搜索