C++ Primer第五版筆記——重載new和delete

要想掌握重載new和delete的方法,首先要對new和delete表達式的工作機理有更多瞭解,當執行一條new/delete表達式時:

string* sp = new string("hello");
string* arr = new string[10];
delete sp;
delete[] arr;

對new來說實際執行了三個步驟:
第一步、new表達式調用一個operator new(或者 operator new[])的標準庫函數。該函數分配一塊足夠大的、未命名的、原始的內存空間以便於存儲特定類型的對象(或者對象數組);
第二步、編譯器運行相應的構造函數以構造這些對象,併爲其傳入初始值;
第三步、對象被分配了空間並構造完成,返回一個指向該對象的指針。
對delete來說實際執行了兩步操作:
第一步、對sp所指對象或者arr所指的對象數組中的元素執行對應的析構操作;
第二步、編譯器調用operator delete(或者operator delete[])的標準庫函數釋放內存空間。
  應用程序可以在全局區域中定義operator new和operator delete函數(這時程序就擔當起控制動態內存分配的職責,這兩函數必須是正確的),也可以將他們定義爲成員函數。當編譯器發現一條new或delete表達式時,將在程序中尋找可供調用的operator函數,如果被分配的類型是類類型,則首先在該類及其基類中查找,沒有找到則會在全局作用域中查找(也可以使用::運算符限制直接執行全局區域中的函數),仍然沒有則會使用標準庫定義的函數。


operator new 接口和operator delete 接口
  標準庫定義了operator new函數和operator delete函數的8個重載版本。其中前4個版本可能拋出bad_alloc異常,後4個版本則不會拋出異常:

//這些版本可能拋出異常
void* operator new(size_t);							//分配一個對象
void* operator new[](size_t);						//分配一個數組
void* operator delete(void*) noexcept;		//釋放一個對象
void* operator delete[](void*) noexcept;		//釋放一個數組

//這些版本不會拋出異常
void* operator new(size_t,nothrow_t&) noexcept;
void* operator new[](size_t,nothrow_t&) noexcept;
void* operator delete(void*,nothrow_t&) noexcept;
void* operator delete[](void*,nothrow_t&) noexcept;

對於operator new和operator new[]函數來說,它們的返回值必須是void*,第一個形參的類型必須是size_t且該形參不能含有默認實參。當編譯器調用前者時,把存儲指定類型對象所需的字節數傳給size_t形參;當編譯器調用後者時,傳入函數的則是存儲數組中所有元素所需的空間。儘管在一般情況下我們可以自定義具有任何形參的operator new,但是以下版本不能被重載:

void* operator new(size_t,void*);

對於operator delete和operator delete[]函數來說,它們的返回類型必須是void,第一個形參類型必須是void*。執行一條delete表達式將調用相應的operator函數,並用指向待釋放內存的指針來初始化void*形參。
  當將這兩個函數定義爲類的成員時,該函數可以包含另一個size_t的形參,此時,該形參的初始值是第一個形參指向的對象的字節數。size_t形參可用於刪除繼承體系中的對象。如果基類有一個虛析構函數,則傳遞給operator delete的字節數將因待刪除指針所指向的對象的動態類型的不同而有所區別。而且,實際運行的operator delete函數版本也由對象的動態類型決定。


malloc函數和free函數
  當定義了自己的全局operator new或operator delete後,必須以某種方式執行分配內存與釋放內存的操作,爲此可以使用malloc和free函數,c++從c語言中繼承這些函數,並將其定義在cstdlib頭文件中。
  malloc函數接受一個表示待分配字節數的size_t,返回指向分配空間的指針或者返回0以表示分配失敗。free接受一個void*,它是malloc返回的指針的副本,free將相關內存返回給系統(調用free(0)沒有意義)。


例子:

void* operator new(size_t size){
	if(void* mem = malloc(size)){
		return mem;
	}
	else{
		throw bad_malloc();	
	}
}

void operator delete(void* mem) noexcept {
	free(mem);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章