一 new操作符的概念
我們通常講的new是指的是new operator,其實(shí)還有另外兩個(gè)概念,operator new 和 placement new。
1、new operator
我們?cè)谑褂胣ew operator的時(shí)候,實(shí)際上是執(zhí)行了三個(gè)步驟:
1)調(diào)用operator new分配內(nèi)存 ;2)調(diào)用構(gòu)造函數(shù)生成類對(duì)象;3)返回相應(yīng)指針。
2、operator new
所以說(shuō)operator new做的事情是new operator的一部分。
operator new的原型是
Void* operator new(size_t size);
函數(shù)的返回值是void, 因?yàn)檫@個(gè)函數(shù)返回的是指針。這個(gè)指針指向原生的,為初始化的內(nèi)存。其語(yǔ)義就像malloc。實(shí)際上它內(nèi)部調(diào)用的就是malloc 。參數(shù)size 指定待分配的內(nèi)存大小。
你 可以重載這個(gè)函數(shù)(注意是重載operator new,而不能重載new operator)。operator new默認(rèn)情況下首先調(diào)用分配內(nèi)存的代碼,嘗試得到一段堆上的空間,如果成功就返回,如果失敗,則轉(zhuǎn)而去調(diào)用一個(gè)new_hander,然后繼續(xù)重復(fù)前面 過(guò)程。你可以在重載的時(shí)候加上額外的參數(shù),但是第一個(gè)參數(shù)類型必須是size_t.例如:
class Fruit
{
public:
void operator new(size_t size)
{
cout<<"operator new function"<<endl;
return ::operator new(size);
}
};
Fruit* pf = new Fruit;
這里通過(guò)::operator new調(diào)用了原有的全局的new,實(shí)現(xiàn)了在分配內(nèi)存之前輸出一句話。全局的operator new也是可以重載的,但這樣一來(lái)就不能再遞歸的使用new來(lái)分配內(nèi)存,而只能使用malloc了:
void* operator new(size_t size)
{
cout<<"global operator new function"<<endl;
return malloc(size);
}
相應(yīng)的,delete也有delete operator和operator delete之分,后者也是可以重載的。并且,如果重載了operator new,就應(yīng)該也相應(yīng)的重載operator delete,這是良好的編程習(xí)慣。
二 placement new
placement new是用來(lái)實(shí)現(xiàn)定位構(gòu)造的,因此可以實(shí)現(xiàn)new operator三步操作中的第二步。
其 實(shí)它也只是operator new的一個(gè)重載的版本,只是我們很少用到它。如果你想在已經(jīng)分配的內(nèi)存中創(chuàng)建一個(gè)對(duì)象,使用new時(shí)行不通的。也就是說(shuō)placement new允許你在一個(gè)已經(jīng)分配好的內(nèi)存中(?;蛘叨阎校?gòu)造一個(gè)新的對(duì)象。原型中void*p實(shí)際上就是指向一個(gè)已經(jīng)分配好的內(nèi)存緩沖區(qū)的的首地址。
我 們知道使用new操作符分配內(nèi)存需要在堆中查找足夠大的剩余空間,這個(gè)操作速度是很慢的,而且有可能出現(xiàn)無(wú)法分配內(nèi)存的異常(空間不夠)。 placement new就可以解決這個(gè)問(wèn)題。我們構(gòu)造對(duì)象都是在一個(gè)預(yù)先準(zhǔn)備好了的內(nèi)存緩沖區(qū)中進(jìn)行,不需要查找內(nèi)存,內(nèi)存分配的時(shí)間是常數(shù);而且不會(huì)出現(xiàn)在程序運(yùn)行中途 出現(xiàn)內(nèi)存不足的異常。所以,placement new非常適合那些對(duì)時(shí)間要求比較高,長(zhǎng)時(shí)間運(yùn)行不希望被打斷的應(yīng)用程序。
使用方法如下:
- 緩沖區(qū)提前分配
可以使用堆的空間,也可以使用棧的空間,所以分配方式有如下兩種:
class Fruit{…};
char buf=new char[Nsizeof(Fruit)+sizeof(int)];或者char buf[N*sizeof(Fruit)+sizeof(int)]; - 對(duì)象的構(gòu)造
Fruit * pf=new(buf) Fruit; - 對(duì)象的銷毀
一旦這個(gè)對(duì)象使用完畢,你必須顯式的調(diào)用類的析構(gòu)函數(shù)進(jìn)行銷毀對(duì)象。但此時(shí)內(nèi)存空間不會(huì)被釋放,以便其他的對(duì)象的構(gòu)造。
pf->~Fruit(); - 內(nèi)存的釋放
如果緩沖區(qū)在堆中,那么調(diào)用delete[] buf;進(jìn)行內(nèi)存的釋放;如果在棧中,那么在其作用域內(nèi)有效,跳出作用域,內(nèi)存自動(dòng)釋放。